/** @file
  File for USBFN protocol implementation.

@copyright
  INTEL CONFIDENTIAL
  Copyright 2015 - 2019 Intel Corporation.

  The source code contained or described herein and all documents related to the
  source code ("Material") are owned by Intel Corporation or its suppliers or
  licensors. Title to the Material remains with Intel Corporation or its suppliers
  and licensors. The Material may contain trade secrets and proprietary and
  confidential information of Intel Corporation and its suppliers and licensors,
  and is protected by worldwide copyright and trade secret laws and treaty
  provisions. No part of the Material may be used, copied, reproduced, modified,
  published, uploaded, posted, transmitted, distributed, or disclosed in any way
  without Intel's prior express written permission.

  No license under any patent, copyright, trade secret or other intellectual
  property right is granted to or conferred upon you by disclosure or delivery
  of the Materials, either expressly, by implication, inducement, estoppel or
  otherwise. Any license under such intellectual property rights must be
  express and approved by Intel in writing.

  Unless otherwise agreed by Intel in writing, you may not remove or alter
  this notice or any other notice embedded in Materials by Intel or
  Intel's suppliers or licensors in any way.

  This file contains a 'Sample Driver' and is licensed as such under the terms
  of your license agreement with Intel or your vendor. This file may be modified
  by the user, subject to the additional terms of the license agreement.

@par Specification Reference:
**/

#include "UsbDeviceDxe.h"

/* 16 bytes in a guid x 2 characters per byte, 4 chars for dashes and a NUL */
#define CHARS_IN_GUID (sizeof(GUID) * 2 + 4 + 1)

/* Strings that get sent with the USB Connection */
static CHAR16 mUsbFnDxeMfgString[]        = L"Intel Corporation";
static CHAR16 mUsbFnDxeProductString[]    = L"AmberLake";

/**
 * Duplicated from MiscSystemManufacturerData.c Some parts of it will
 * replaced with device-specific unique values.
 */
static GUID mSmBiosUniqueGuid = {
        0x5e24fe9c, 0xc8d0, 0x45bd, 0xa7, 0x9f, 0x54, 0xea, 0x5f, 0xbd, 0x3d, 0x97
    };

EFI_USBFN_IO_PROTOCOL         mUsbFunIoProtocol = {
  EFI_USBFN_IO_PROTOCOL_REVISION,
  DetectPort,
  ConfigureEnableEndpoints,
  GetEndpointMaxPacketSize,
  GetDeviceInfo,
  GetVendorIdProductId,
  AbortTransfer,
  GetEndpointStallState,
  SetEndpointStallState,
  EventHandler,
  Transfer,
  GetMaxTransferSize,
  AllocateTransferBuffer,
  FreeTransferBuffer,
  StartController,
  StopController,
  SetEndpointPolicy,
  GetEndpointPolicy,
  ConfigureEnableEndpointsEx
};


/**
Debug Start
**/
EFI_STATUS
PrintEventBuffer(
  IN  EFI_USBFN_IO_PROTOCOL  *This
  )
{
  UINT32                          EventCount;
  USB_XDCI_DEV_CONTEXT            *UsbFuncIoDevPtr;
  XDCI_CORE_HANDLE                *XdciCorePtr;
  USB_DEV_CORE                    *UsbDeviceCorePtr;
  UINT32                          Index;
  UINT32                          *DbBufPtr;

  UsbFuncIoDevPtr = USBFUIO_CONTEXT_FROM_PROTOCOL (This);

  UsbDeviceCorePtr = UsbFuncIoDevPtr->DrvCore;
  XdciCorePtr = UsbDeviceCorePtr->controller_handle;

  EventCount = usb_reg_read ((UINT32)UsbFuncIoDevPtr->XdciMmioBarAddr, DWC_XDCI_EVNTCOUNT_REG(0));
  //DEBUG ((USB_FUIO_DEBUG_EVENT_D, "\n ==>> EventCount = 0x%08x \n", EventCount));

  DbBufPtr = (UINT32*)(UINTN)XdciCorePtr->current_event_buffer;
  XdciCorePtr = UsbDeviceCorePtr->controller_handle;
  DEBUG ((USB_FUIO_DEBUG_EVENT_D, "FUEV:: XdciCorePtr->aligned_event_buffers 0x%08x\n", (UINTN)XdciCorePtr->aligned_event_buffers));
  DEBUG ((USB_FUIO_DEBUG_EVENT_D, "FUEV:: DUMP BUF_S\n"));
  for (Index = 0; Index < ((EventCount / 4) + 1); Index++) {
    DEBUG ((USB_FUIO_DEBUG_EVENT_D, "0x%08x\n", DbBufPtr[Index]));
  }
  DEBUG ((USB_FUIO_DEBUG_EVENT_D, "FUEV:: DUMP BUF_E\n"));

  return EFI_SUCCESS;
}

/**
Debug End
**/

/**
  Returns information about what type of device was attached.

  @param[in]  This               A pointer to the EFI_USBFN_IO_PROTOCOL instance.
  @param[out] PortType           Returns the USB port type.


  @retval EFI_SUCCESS            The operation completed successfully.
  @retval EFI_INVALID_PARAMETER  A parameter is invalid.
  @retval EFI_DEVICE_ERROR       The physical device reported an error.
  @retval EFI_NOT_READY          The physical device is busy or not ready to
                                 process this request or the device is not
                                 attached to the host.


**/
EFI_STATUS
EFIAPI
DetectPort (
  IN  EFI_USBFN_IO_PROTOCOL  *This,
  OUT EFI_USBFN_PORT_TYPE    *PortType
  )
{
  USB_XDCI_DEV_CONTEXT  *UsbFuncIoDevPtr;
  EFI_STATUS            Status;
  UINT8                 Value8;

  DEBUG ((USB_FUIO_DEBUG_INFO, "DetectPort - Entry\n"));

  UsbFuncIoDevPtr = USBFUIO_CONTEXT_FROM_PROTOCOL (This);

  // USBSRCDETRSLT Bit[5:2]
  // Result of USB HW Source Detection algorithm
  // Power-Domain: VRTC
  // Result of USB HW Source Detection algorithm :
  // 0000 = Not determined
  // 0001 = SDP Attached
  // 0010 = DCP Attached
  // 0011 = CDP Attached
  // 0100 = ACA Attached
  // 0101 = SE1 Attached
  // 0110 = MHL Attached
  // 0111 = Floating D+/D- Attached
  // 1000 = Other Attached
  // 1001 = DCP detected by ext. USB PHY
  // 1010-1111 = Rsvd
  // Reset: 0000B

  Value8 = 1;
  if ((Value8 & 0x03) != 0x02) {
    *PortType = EfiUsbUnknownPort;
    Status = EFI_NOT_READY;
    goto out;
  }

  Value8 = Value8 >> 2 & 0x0f;
  Status = EFI_SUCCESS;
  switch (Value8) {
    case 1:
      *PortType = EfiUsbStandardDownstreamPort;
      break;
    case 2:
      *PortType = EfiUsbDedicatedChargingPort;
      break;
    case 3:
      *PortType = EfiUsbChargingDownstreamPort;
      break;

    case 4:
    case 5:
    case 6:
    case 7:
    case 8:
    case 9:
      *PortType = EfiUsbUnknownPort;
      break;
    case 0:
    case 10:
    case 11:
    case 12:
    case 13:
    case 14:
    case 15:
      *PortType = EfiUsbUnknownPort;
      Status = EFI_NOT_READY;
     break;
  }

out:
  DEBUG ((USB_FUIO_DEBUG_INFO, "DetectPort - Exit\n"));
  return EFI_SUCCESS;
}


/**
  The AllocateTransferBuffer function allocates a memory region of Size bytes
  and returns the address of the allocated memory that satisfies underlying
  controller requirements in the location referenced by Buffer.

  @param[in] This               A pointer to the EFI_USBFN_IO_PROTOCOL instance.
  @param[in] Size               The number of bytes to allocate for the transfer
                                buffer.
  @param[in] Buffer             A pointer to a pointer to the allocated buffer
                                if the call succeeds; undefined otherwise.

  @retval EFI_SUCCESS           The operation completed successfully.
  @retval EFI_INVALID_PARAMETER A parameter is invalid.
  @retval The requested transfer buffer could not be allocated.

**/
EFI_STATUS
EFIAPI
AllocateTransferBuffer (
  IN EFI_USBFN_IO_PROTOCOL    *This,
  IN UINTN                    Size,
  OUT VOID                    **Buffer
  )
{
  EFI_STATUS            Status;
  USB_XDCI_DEV_CONTEXT  *UsbFuncIoDevPtr;
  VOID                  *AllocateBufferPtr;
  USB_MEM_NODE          *NodePtr;

  DEBUG ((USB_FUIO_DEBUG_INFO, "AllocateTransferBuffer - Entry\n"));

  UsbFuncIoDevPtr = USBFUIO_CONTEXT_FROM_PROTOCOL (This);

  if (Size == 0) {
    Status = EFI_INVALID_PARAMETER;
    goto ErrorExit;
  }

  AllocateBufferPtr = AllocateZeroPool (Size);

  if (AllocateBufferPtr == NULL) {
    Status = EFI_OUT_OF_RESOURCES;
    goto ErrorExit;
  }

  //
  // Create new node
  //
  Status = InsertNewNodeToHead (This, &NodePtr);
  if (EFI_ERROR (Status)) {
    Status = EFI_OUT_OF_RESOURCES;
    goto ErrorExit;
  }

  NodePtr->Size = Size;
  NodePtr->AllocatePtr = AllocateBufferPtr;

  *Buffer = AllocateBufferPtr;

  DEBUG ((USB_FUIO_DEBUG_INFO, "AllocateTransferBuffer addr 0x%08x\n", AllocateBufferPtr));
  DEBUG ((USB_FUIO_DEBUG_INFO, "AllocateTransferBuffer - Exit\n"));
  return EFI_SUCCESS;

ErrorExit:

  DEBUG ((USB_FUIO_DEBUG_ERROR, "AllocateTransferBuffer - ERRROR %r\n",Status));
  return Status;
}


/**
  Deallocates the memory allocated for the transfer buffer by
  AllocateTransferBuffer function.

  @param[in] This               A pointer to the EFI_USBFN_IO_PROTOCOL instance.
  @param[in] Buffer             Buffer Pointer to the transfer buffer
                                to deallocate.
  @retval EFI_SUCCESS           The function returned successfully.
  @retval EFI_INVALID_PARAMETER A parameter is invalid.

**/
EFI_STATUS
EFIAPI
FreeTransferBuffer (
  IN EFI_USBFN_IO_PROTOCOL    *This,
  IN VOID                     *Buffer
  )
{
  EFI_STATUS            Status;
  USB_XDCI_DEV_CONTEXT  *UsbFuncIoDevPtr;

  UsbFuncIoDevPtr = USBFUIO_CONTEXT_FROM_PROTOCOL (This);
  DEBUG ((USB_FUIO_DEBUG_LOAD, "FreeTransferBuffer - Entry\n"));

  Status = RemoveNode (This, Buffer);
  if (EFI_ERROR(Status)) {
    DEBUG ((USB_FUIO_DEBUG_LOAD, "FreeTransferBuffer - ERROR\n"));
    return EFI_INVALID_PARAMETER;
  }

  DEBUG ((USB_FUIO_DEBUG_LOAD, "FreeTransferBuffer - Exit\n"));
  return EFI_SUCCESS;
}

/**
  Frees the input InterfaceInfo structure (and all sub-elements of that structure.)

  @param[in] InterfaceInfo         A pointer to EFI_USB_INTERFACE_INFO instance.

  @retval - None

**/
VOID
FreeEndpointDescriptorTable (
  IN EFI_USB_SUPERSPEED_ENDPOINT_DESCRIPTOR *InterfaceInfo
) 
{
  if (InterfaceInfo == NULL) {
    return;
  }
  DEBUG((USB_FUIO_DEBUG_INFO, "[%a] Start.\n", __FUNCTION__));
  if (InterfaceInfo->EndpointDescriptor != NULL) {
    //Free the endpoint table if present
    if (InterfaceInfo->EndpointCompanionDescriptor != NULL) {
      DEBUG((USB_FUIO_DEBUG_INFO, "[%a] Freeing InterfaceInfo->EndpointDescriptorTable.\n", __FUNCTION__));
      FreePool(InterfaceInfo->EndpointCompanionDescriptor);
    }
    DEBUG((USB_FUIO_DEBUG_INFO, "[%a] Freeing InterfaceInfo->EndpointDescriptorTable\n", __FUNCTION__));
    FreePool(InterfaceInfo->EndpointDescriptor);
 }
}
/**
  Frees the input InterfaceInfo structure (and all sub-elements of that structure.)

  @param[in] InterfaceInfo         A pointer to EFI_USB_INTERFACE_INFO instance.

  @retval - None

**/
VOID
FreeSSInterfaceInfo (
  IN EFI_USB_SUPERSPEED_INTERFACE_INFO *InterfaceInfo
  ) 
{
  if (InterfaceInfo == NULL) {
    return;
  }
  DEBUG((USB_FUIO_DEBUG_INFO, "[%a] Start.\n", __FUNCTION__));
  if (InterfaceInfo->InterfaceDescriptor != NULL) {
    //Free the endpoint table if present
    if (InterfaceInfo->EndpointDescriptorTable != NULL) {
      for (UINTN EndpointIdx = 0; EndpointIdx < InterfaceInfo->InterfaceDescriptor->NumEndpoints; EndpointIdx++) {
        //Free the endpoint table entry if present
        if (InterfaceInfo->EndpointDescriptorTable[EndpointIdx] != NULL) {
          DEBUG((USB_FUIO_DEBUG_INFO, "[%a] Freeing InterfaceInfo->EndpointDescriptorTable[%d].\n", __FUNCTION__, EndpointIdx));
          FreeEndpointDescriptorTable(InterfaceInfo->EndpointDescriptorTable[EndpointIdx]);
          FreePool(InterfaceInfo->EndpointDescriptorTable[EndpointIdx]);
        }
      }
      DEBUG((USB_FUIO_DEBUG_INFO, "[%a] Freeing InterfaceInfo->EndpointDescriptorTable\n", __FUNCTION__));
      FreePool(InterfaceInfo->EndpointDescriptorTable);
    }
    DEBUG((USB_FUIO_DEBUG_INFO, "[%a] Freeing InterfaceInfo->InterfaceDescriptor\n", __FUNCTION__));
    FreePool(InterfaceInfo->InterfaceDescriptor);
  }
}

/**
  Frees the input ConfigInfo structure (and all sub-elements of that structure.)

  @param[in] ConfigInfo         A pointer to EFI_USB_CONFIG_INFO instance.

  @retval - None

**/
VOID
FreeSSConfigInfo(
IN EFI_USB_SUPERSPEED_CONFIG_INFO *ConfigInfo
) {
  if (ConfigInfo == NULL) {
    return;
  }
  DEBUG((USB_FUIO_DEBUG_INFO, "[%a] Start.\n", __FUNCTION__));
  if (ConfigInfo->ConfigDescriptor != NULL) {
    //Free the interface table if present.
    if (ConfigInfo->InterfaceInfoTable != NULL) {
      for (UINTN InterfaceIdx = 0; InterfaceIdx < ConfigInfo->ConfigDescriptor->NumInterfaces; InterfaceIdx++) {
        //Free the interface table entry if present
        if (ConfigInfo->InterfaceInfoTable[InterfaceIdx] != NULL) {
          DEBUG((USB_FUIO_DEBUG_INFO, "[%a] Freeing ConfigInfo->InterfaceInfoTable[%d].\n", __FUNCTION__, InterfaceIdx));
          FreeSSInterfaceInfo(ConfigInfo->InterfaceInfoTable[InterfaceIdx]);
          FreePool(ConfigInfo->InterfaceInfoTable[InterfaceIdx]);
        }
      }
      DEBUG((USB_FUIO_DEBUG_INFO, "[%a] Freeing ConfigInfo->InterfaceInfoTable\n", __FUNCTION__));
      FreePool(ConfigInfo->InterfaceInfoTable);
    }
    DEBUG((USB_FUIO_DEBUG_INFO, "[%a] Freeing ConfigInfo->ConfigDescriptor\n", __FUNCTION__));
    FreePool(ConfigInfo->ConfigDescriptor);
  }
}

/**
  Frees the input DeviceInfo structure (and all sub-elements of that structure.)

  @param[in] DeviceInfo         A pointer to EFI_USB_DEVICE_INFO instance.

  @retval - None

**/
VOID
FreeSSDeviceInfo(
IN EFI_USB_SUPERSPEED_DEVICE_INFO *DeviceInfo
) {
  if (DeviceInfo == NULL) {
    return;
  }
  DEBUG((USB_FUIO_DEBUG_INFO, "[%a] Start.\n", __FUNCTION__));
  if (DeviceInfo->DeviceDescriptor != NULL) {
    //Free the config info table if present.
    if (DeviceInfo->ConfigInfoTable != NULL) {
      for (UINTN ConfigIdx = 0; ConfigIdx < DeviceInfo->DeviceDescriptor->NumConfigurations; ConfigIdx++) {
        //Free the config table entry if present
        if (DeviceInfo->ConfigInfoTable[ConfigIdx] != NULL) {
          DEBUG((USB_FUIO_DEBUG_INFO, "[%a] Freeing DeviceInfo->ConfigInfoTable[%d].\n", __FUNCTION__, ConfigIdx));
          FreeSSConfigInfo(DeviceInfo->ConfigInfoTable[ConfigIdx]);
          FreePool(DeviceInfo->ConfigInfoTable[ConfigIdx]);
        }
      }
      DEBUG((USB_FUIO_DEBUG_INFO, "[%a] Freeing DeviceInfo->ConfigInfoTable\n", __FUNCTION__));
      FreePool(DeviceInfo->ConfigInfoTable);
    }
    DEBUG((USB_FUIO_DEBUG_INFO, "[%a] Freeing DeviceInfo->DeviceDescriptor\n", __FUNCTION__));
    FreePool(DeviceInfo->DeviceDescriptor);
  }
}

/**
  Frees the input InterfaceInfo structure (and all sub-elements of that structure.)

  @param[in] InterfaceInfo         A pointer to EFI_USB_INTERFACE_INFO instance.

  @retval - None

**/
VOID
FreeInterfaceInfo(
  IN EFI_USB_INTERFACE_INFO *InterfaceInfo
) {
  if (InterfaceInfo == NULL) {
    return;
  }
  DEBUG((USB_FUIO_DEBUG_INFO, "[%a] Start.\n", __FUNCTION__));
  if (InterfaceInfo->InterfaceDescriptor != NULL) {
    //Free the endpoint table if present
    if (InterfaceInfo->EndpointDescriptorTable != NULL) {
      for (UINTN EndpointIdx=0; EndpointIdx < InterfaceInfo->InterfaceDescriptor->NumEndpoints; EndpointIdx++) {
        //Free the endpoint table entry if present
        if (InterfaceInfo->EndpointDescriptorTable[EndpointIdx] != NULL) {
          DEBUG((USB_FUIO_DEBUG_INFO, "[%a] Freeing InterfaceInfo->EndpointDescriptorTable[%d].\n", __FUNCTION__, EndpointIdx));
          FreePool(InterfaceInfo->EndpointDescriptorTable[EndpointIdx]);
        }
      }
      DEBUG((USB_FUIO_DEBUG_INFO, "[%a] Freeing InterfaceInfo->EndpointDescriptorTable\n", __FUNCTION__));
      FreePool(InterfaceInfo->EndpointDescriptorTable);
    }
    DEBUG((USB_FUIO_DEBUG_INFO, "[%a] Freeing InterfaceInfo->InterfaceDescriptor\n", __FUNCTION__));
    FreePool(InterfaceInfo->InterfaceDescriptor);
  }
}

/**
  Frees the input ConfigInfo structure (and all sub-elements of that structure.)

  @param[in] ConfigInfo         A pointer to EFI_USB_CONFIG_INFO instance.

  @retval - None

**/
VOID
FreeConfigInfo(
  IN EFI_USB_CONFIG_INFO *ConfigInfo
) {
  if (ConfigInfo == NULL) {
    return;
  }
  DEBUG((USB_FUIO_DEBUG_INFO, "[%a] Start.\n", __FUNCTION__));
  if (ConfigInfo->ConfigDescriptor != NULL) {
    //Free the interface table if present.
    if (ConfigInfo->InterfaceInfoTable != NULL) {
      for (UINTN InterfaceIdx = 0; InterfaceIdx < ConfigInfo->ConfigDescriptor->NumInterfaces; InterfaceIdx++) {
        //Free the interface table entry if present
        if (ConfigInfo->InterfaceInfoTable[InterfaceIdx] != NULL) {
          DEBUG((USB_FUIO_DEBUG_INFO, "[%a] Freeing ConfigInfo->InterfaceInfoTable[%d].\n", __FUNCTION__, InterfaceIdx));
          FreeInterfaceInfo(ConfigInfo->InterfaceInfoTable[InterfaceIdx]);
          FreePool(ConfigInfo->InterfaceInfoTable[InterfaceIdx]);
        }
      }
      DEBUG((USB_FUIO_DEBUG_INFO, "[%a] Freeing ConfigInfo->InterfaceInfoTable\n", __FUNCTION__));
      FreePool(ConfigInfo->InterfaceInfoTable);
    }
    DEBUG((USB_FUIO_DEBUG_INFO, "[%a] Freeing ConfigInfo->ConfigDescriptor\n", __FUNCTION__));
    FreePool(ConfigInfo->ConfigDescriptor);
  }
}

/**
  Frees the input DeviceInfo structure (and all sub-elements of that structure.)

  @param[in] DeviceInfo         A pointer to EFI_USB_DEVICE_INFO instance.

  @retval - None

**/
VOID
FreeDeviceInfo(
  IN EFI_USB_DEVICE_INFO *DeviceInfo
) {
  if (DeviceInfo == NULL) {
    return;
  }
  DEBUG((USB_FUIO_DEBUG_INFO, "[%a] Start.\n", __FUNCTION__));
  if (DeviceInfo->DeviceDescriptor != NULL) {
    //Free the config info table if present.
    if (DeviceInfo->ConfigInfoTable != NULL) {
      for (UINTN ConfigIdx = 0; ConfigIdx < DeviceInfo->DeviceDescriptor->NumConfigurations; ConfigIdx++) {
        //Free the config table entry if present
        if(DeviceInfo->ConfigInfoTable[ConfigIdx] != NULL) {
          DEBUG((USB_FUIO_DEBUG_INFO, "[%a] Freeing DeviceInfo->ConfigInfoTable[%d].\n", __FUNCTION__, ConfigIdx));
          FreeConfigInfo(DeviceInfo->ConfigInfoTable[ConfigIdx]);
          FreePool(DeviceInfo->ConfigInfoTable[ConfigIdx]);
        }
      }
      DEBUG((USB_FUIO_DEBUG_INFO, "[%a] Freeing DeviceInfo->ConfigInfoTable\n", __FUNCTION__));
      FreePool(DeviceInfo->ConfigInfoTable);
    }
    DEBUG((USB_FUIO_DEBUG_INFO, "[%a] Freeing DeviceInfo->DeviceDescriptor\n", __FUNCTION__));
    FreePool(DeviceInfo->DeviceDescriptor);
  }
}

/**
  Performs a deep-copy of the Source EFI_USB_INTERFACE_INFO structure into the Target EFI_USB_INTERFACE_INFO structure.

  1. Allocates and copies the Endpoint Descriptor
  2. Allocates and copies the Endpoint CompanionDescriptor

  @param[in] SourceEndPointDescriptor   A pointer to EFI_USB_INTERFACE_INFO instance to copy  from.
  @param[in] TargetEndPointDescriptor   A pointer to EFI_USB_INTERFACE_INFO instance to copy into.

  @retval - EFI_SUCCESS - copy created successfully.
  @retval - Other - failed to create copy.
**/
EFI_STATUS
CopySSEndPointDescriptor (
IN EFI_USB_SUPERSPEED_ENDPOINT_DESCRIPTOR *SourceEndPointDescriptor,
IN EFI_USB_SUPERSPEED_ENDPOINT_DESCRIPTOR *TargetEndPointDescriptor
)
{
  EFI_STATUS Status;

  if (SourceEndPointDescriptor == NULL || TargetEndPointDescriptor == NULL) {
    return EFI_INVALID_PARAMETER;
  }

  DEBUG((USB_FUIO_DEBUG_INFO, "[%a] Start.\n", __FUNCTION__));

  //Allocate and copy Interface Descriptor
  TargetEndPointDescriptor->EndpointDescriptor = AllocateZeroPool(sizeof(EFI_USB_ENDPOINT_DESCRIPTOR));
  if (TargetEndPointDescriptor->EndpointDescriptor == NULL) {
    Status = EFI_OUT_OF_RESOURCES;
    goto Cleanup;
  }
  CopyMem(TargetEndPointDescriptor->EndpointDescriptor, SourceEndPointDescriptor->EndpointDescriptor, sizeof(EFI_USB_ENDPOINT_DESCRIPTOR));

  DEBUG((USB_FUIO_DEBUG_INFO, "[%a] EndpointDescriptor allocated and copied.\n", __FUNCTION__));

  //Allocate space for EndpointDescriptorTable
  TargetEndPointDescriptor->EndpointCompanionDescriptor = AllocateZeroPool(sizeof(EFI_USB_SUPERSPEED_ENDPOINT_COMPANION_DESCRIPTOR));
  if (TargetEndPointDescriptor->EndpointCompanionDescriptor == NULL) {
    Status = EFI_OUT_OF_RESOURCES;
    goto Cleanup;
  }
  //Copy Endpoint Descriptors
  Status = EFI_SUCCESS;
  
  //Copy the endpoint descriptor
  CopyMem(TargetEndPointDescriptor->EndpointCompanionDescriptor, SourceEndPointDescriptor->EndpointCompanionDescriptor, sizeof(EFI_USB_SUPERSPEED_ENDPOINT_COMPANION_DESCRIPTOR));
    DEBUG((USB_FUIO_DEBUG_INFO, "[%a] EndpointCompanionDescriptor allocated and copied.\n", __FUNCTION__));
Cleanup:
  DEBUG((USB_FUIO_DEBUG_INFO, "[%a] done. Status %r\n", __FUNCTION__, Status));
  if (EFI_ERROR(Status)) {
    FreeEndpointDescriptorTable(TargetEndPointDescriptor);
  }
  return Status;
}
/**
  Performs a deep-copy of the Source EFI_USB_INTERFACE_INFO structure into the Target EFI_USB_INTERFACE_INFO structure.

  1. Allocates and copies the Interface Descriptor
  2. Allocates and copies all entries in the EndpointDescriptorTable.

  @param[in] SourceInterfaceInfo   A pointer to EFI_USB_INTERFACE_INFO instance to copy  from.
  @param[in] TargetInterfaceInfo   A pointer to EFI_USB_INTERFACE_INFO instance to copy into.

  @retval - EFI_SUCCESS - copy created successfully.
  @retval - Other - failed to create copy.
**/
EFI_STATUS
CopyInterfaceDescriptor(
  IN EFI_USB_INTERFACE_INFO *SourceInterfaceInfo,
  IN EFI_USB_INTERFACE_INFO *TargetInterfaceInfo
)
{
  EFI_STATUS Status;

  if(SourceInterfaceInfo == NULL || TargetInterfaceInfo == NULL) {
    return EFI_INVALID_PARAMETER;
  }

  DEBUG((USB_FUIO_DEBUG_INFO, "[%a] Start.\n", __FUNCTION__));

  //Allocate and copy Interface Descriptor
  TargetInterfaceInfo->InterfaceDescriptor = AllocateZeroPool(sizeof(EFI_USB_INTERFACE_DESCRIPTOR));
  if (TargetInterfaceInfo->InterfaceDescriptor == NULL) {
    Status = EFI_OUT_OF_RESOURCES;
    goto Cleanup;
  }
  CopyMem(TargetInterfaceInfo->InterfaceDescriptor, SourceInterfaceInfo->InterfaceDescriptor, sizeof(EFI_USB_INTERFACE_DESCRIPTOR));

  DEBUG((USB_FUIO_DEBUG_INFO, "[%a] InterfaceDescriptor allocated and copied.\n", __FUNCTION__));

  //Allocate space for EndpointDescriptorTable
  TargetInterfaceInfo->EndpointDescriptorTable = 
    AllocateZeroPool(sizeof(EFI_USB_ENDPOINT_DESCRIPTOR*) * TargetInterfaceInfo->InterfaceDescriptor->NumEndpoints);
  if (TargetInterfaceInfo->EndpointDescriptorTable == NULL) {
    Status = EFI_OUT_OF_RESOURCES;
    goto Cleanup;
  }

  DEBUG((USB_FUIO_DEBUG_INFO, "[%a] EndpointDescriptorTable allocated (%d entries).\n", __FUNCTION__, 
    TargetInterfaceInfo->InterfaceDescriptor->NumEndpoints));

  //Copy Endpoint Descriptors
  Status = EFI_SUCCESS;
  for (UINTN EndpointIdx = 0; EndpointIdx < TargetInterfaceInfo->InterfaceDescriptor->NumEndpoints; EndpointIdx++) {
    //Allocate table entry
    TargetInterfaceInfo->EndpointDescriptorTable[EndpointIdx] =
      AllocateZeroPool(sizeof(EFI_USB_ENDPOINT_DESCRIPTOR));
    if (TargetInterfaceInfo->EndpointDescriptorTable[EndpointIdx] == NULL) {
      Status = EFI_OUT_OF_RESOURCES;
      goto Cleanup;
    }

    //Copy the endpoint descriptor
    CopyMem(TargetInterfaceInfo->EndpointDescriptorTable[EndpointIdx],
            SourceInterfaceInfo->EndpointDescriptorTable[EndpointIdx],
            sizeof(EFI_USB_ENDPOINT_DESCRIPTOR));
    DEBUG((USB_FUIO_DEBUG_INFO, "[%a] EndpointDescriptorTable[%d] allocated and copied.\n", __FUNCTION__, EndpointIdx));
  }
Cleanup:
  DEBUG((USB_FUIO_DEBUG_INFO, "[%a] done. Status %r\n", __FUNCTION__, Status));
  if (EFI_ERROR(Status)) {
    FreeInterfaceInfo(TargetInterfaceInfo);
  }
  return Status;
}

/**
  Performs a deep-copy of the Source EFI_USB_INTERFACE_INFO structure into the Target EFI_USB_INTERFACE_INFO structure.

  1. Allocates and copies the Interface Descriptor
  2. Allocates and copies all entries in the EndpointDescriptorTable.

  @param[in] SourceInterfaceInfo   A pointer to EFI_USB_INTERFACE_INFO instance to copy  from.
  @param[in] TargetInterfaceInfo   A pointer to EFI_USB_INTERFACE_INFO instance to copy into.

  @retval - EFI_SUCCESS - copy created successfully.
  @retval - Other - failed to create copy.
**/
EFI_STATUS
CopySSInterfaceDescriptor(
IN EFI_USB_SUPERSPEED_INTERFACE_INFO *SourceInterfaceInfo,
IN EFI_USB_SUPERSPEED_INTERFACE_INFO *TargetInterfaceInfo
)
{
  EFI_STATUS Status;

  if (SourceInterfaceInfo == NULL || TargetInterfaceInfo == NULL) {
    return EFI_INVALID_PARAMETER;
  }

  DEBUG((USB_FUIO_DEBUG_INFO, "[%a] Start.\n", __FUNCTION__));

  //Allocate and copy Interface Descriptor
  TargetInterfaceInfo->InterfaceDescriptor = AllocateZeroPool(sizeof(EFI_USB_INTERFACE_DESCRIPTOR));
  if (TargetInterfaceInfo->InterfaceDescriptor == NULL) {
    Status = EFI_OUT_OF_RESOURCES;
    goto Cleanup;
  }
  CopyMem(TargetInterfaceInfo->InterfaceDescriptor, SourceInterfaceInfo->InterfaceDescriptor, sizeof(EFI_USB_INTERFACE_DESCRIPTOR));

  DEBUG((USB_FUIO_DEBUG_INFO, "[%a] InterfaceDescriptor allocated and copied.\n", __FUNCTION__));

  //Allocate space for EndpointDescriptorTable
  TargetInterfaceInfo->EndpointDescriptorTable =
    AllocateZeroPool(sizeof(EFI_USB_SUPERSPEED_ENDPOINT_DESCRIPTOR*)* TargetInterfaceInfo->InterfaceDescriptor->NumEndpoints);
  if (TargetInterfaceInfo->EndpointDescriptorTable == NULL) {
    Status = EFI_OUT_OF_RESOURCES;
    goto Cleanup;
  }

  DEBUG((USB_FUIO_DEBUG_INFO, "[%a] EndpointDescriptorTable allocated (%d entries).\n", __FUNCTION__,
    TargetInterfaceInfo->InterfaceDescriptor->NumEndpoints));

  //Copy Endpoint Descriptors
  Status = EFI_SUCCESS;
  for (UINTN EndpointIdx = 0; EndpointIdx < TargetInterfaceInfo->InterfaceDescriptor->NumEndpoints; EndpointIdx++) {
    //Allocate table entry
    TargetInterfaceInfo->EndpointDescriptorTable[EndpointIdx] =
      AllocateZeroPool(sizeof(EFI_USB_SUPERSPEED_ENDPOINT_DESCRIPTOR));
    if (TargetInterfaceInfo->EndpointDescriptorTable[EndpointIdx] == NULL) {
      Status = EFI_OUT_OF_RESOURCES;
      goto Cleanup;
    }
    //Copy the endpoint descriptor
    Status = CopySSEndPointDescriptor(SourceInterfaceInfo->EndpointDescriptorTable[EndpointIdx], TargetInterfaceInfo->EndpointDescriptorTable[EndpointIdx]);
  }
Cleanup:
  DEBUG((USB_FUIO_DEBUG_INFO, "[%a] done. Status %r\n", __FUNCTION__, Status));
  if (EFI_ERROR(Status)) {
    FreeSSInterfaceInfo(TargetInterfaceInfo);
  }
  return Status;
}
/**
  Performs a deep-copy of the Source EFI_USB_CONFIG_INFO structure into the Target EFI_USB_CONFIG_INFO structure.

  1. Allocates and copies the Config Descriptor
  2. Allocates and copies all entries in the InterfaceInfoTable.

  @param[in] SourceConfigInfo   A pointer to EFI_USB_CONFIG_INFO instance to copy  from.
  @param[in] TargetConfigInfo   A pointer to EFI_USB_CONFIG_INFO instance to copy into.

  @retval - EFI_SUCCESS - copy created successfully.
  @retval - Other - failed to create copy.
**/
EFI_STATUS
CopyConfigDescriptor(
  IN EFI_USB_CONFIG_INFO *SourceConfigInfo,
  IN EFI_USB_CONFIG_INFO *TargetConfigInfo
)
{
  EFI_STATUS Status;

  if (SourceConfigInfo == NULL || TargetConfigInfo == NULL) {
    return EFI_INVALID_PARAMETER;
  }

  DEBUG((USB_FUIO_DEBUG_INFO, "[%a] Start.\n", __FUNCTION__));

  //Allocate and copy ConfigDescriptor
  TargetConfigInfo->ConfigDescriptor = AllocateZeroPool(sizeof(EFI_USB_CONFIG_DESCRIPTOR));
  if (TargetConfigInfo->ConfigDescriptor == NULL) {
    Status = EFI_OUT_OF_RESOURCES;
    goto Cleanup;
  }
  CopyMem(TargetConfigInfo->ConfigDescriptor, SourceConfigInfo->ConfigDescriptor, sizeof(EFI_USB_CONFIG_DESCRIPTOR));

  DEBUG((USB_FUIO_DEBUG_INFO, "[%a] ConfigDescriptor allocated and copied.\n", __FUNCTION__));

  //Allocate space for InterfaceInfoTable
  TargetConfigInfo->InterfaceInfoTable = 
    AllocateZeroPool(sizeof(EFI_USB_INTERFACE_INFO*) * TargetConfigInfo->ConfigDescriptor->NumInterfaces);
  if (TargetConfigInfo->InterfaceInfoTable == NULL) {
    Status = EFI_OUT_OF_RESOURCES;
    goto Cleanup;
  }

  DEBUG((USB_FUIO_DEBUG_INFO, "[%a] InterfaceInfoTable allocated (%d entries).\n", __FUNCTION__, 
    TargetConfigInfo->ConfigDescriptor->NumInterfaces));

  //Copy Interface Table Entries
  Status = EFI_SUCCESS;
  for (UINTN InterfaceIdx = 0; InterfaceIdx < TargetConfigInfo->ConfigDescriptor->NumInterfaces;InterfaceIdx++) {
    //Allocate table entry
    TargetConfigInfo->InterfaceInfoTable[InterfaceIdx] = AllocateZeroPool(sizeof(EFI_USB_INTERFACE_INFO));
    if (TargetConfigInfo->InterfaceInfoTable[InterfaceIdx] == NULL) {
      Status = EFI_OUT_OF_RESOURCES;
      goto Cleanup;
    }

    //Deep-Copy the Interface Descriptor (and sub-structures)
    Status = CopyInterfaceDescriptor(
      SourceConfigInfo->InterfaceInfoTable[InterfaceIdx],
      TargetConfigInfo->InterfaceInfoTable[InterfaceIdx]
    );

    DEBUG((USB_FUIO_DEBUG_INFO, "[%a] InterfaceInfoTable[%d] allocated and copied.\n", __FUNCTION__, InterfaceIdx));
  }
Cleanup:
  DEBUG((USB_FUIO_DEBUG_INFO, "[%a] done. Status %r\n", __FUNCTION__, Status));
  if (EFI_ERROR(Status)) {
    FreeConfigInfo(TargetConfigInfo);
  }
  return Status;
}

/**
  Performs a deep-copy of the Source EFI_USB_CONFIG_INFO structure into the Target EFI_USB_CONFIG_INFO structure.

  1. Allocates and copies the Config Descriptor
  2. Allocates and copies all entries in the InterfaceInfoTable.

  @param[in] SourceConfigInfo   A pointer to EFI_USB_CONFIG_INFO instance to copy  from.
  @param[in] TargetConfigInfo   A pointer to EFI_USB_CONFIG_INFO instance to copy into.

  @retval - EFI_SUCCESS - copy created successfully.
  @retval - Other - failed to create copy.
**/
EFI_STATUS
CopySSConfigDescriptor(
IN EFI_USB_SUPERSPEED_CONFIG_INFO *SourceConfigInfo,
IN EFI_USB_SUPERSPEED_CONFIG_INFO *TargetConfigInfo
)
{
  EFI_STATUS Status;

  if (SourceConfigInfo == NULL || TargetConfigInfo == NULL) {
    return EFI_INVALID_PARAMETER;
  }

  DEBUG((USB_FUIO_DEBUG_INFO, "[%a] Start.\n", __FUNCTION__));

  //Allocate and copy ConfigDescriptor
  TargetConfigInfo->ConfigDescriptor = AllocateZeroPool(sizeof(EFI_USB_CONFIG_DESCRIPTOR));
  if (TargetConfigInfo->ConfigDescriptor == NULL) {
    Status = EFI_OUT_OF_RESOURCES;
    goto Cleanup;
  }
  CopyMem(TargetConfigInfo->ConfigDescriptor, SourceConfigInfo->ConfigDescriptor, sizeof(EFI_USB_CONFIG_DESCRIPTOR));

  DEBUG((USB_FUIO_DEBUG_INFO, "[%a] ConfigDescriptor allocated and copied.\n", __FUNCTION__));

  //Allocate space for InterfaceInfoTable
  TargetConfigInfo->InterfaceInfoTable =
    AllocateZeroPool(sizeof(EFI_USB_SUPERSPEED_INTERFACE_INFO*)* TargetConfigInfo->ConfigDescriptor->NumInterfaces);
  if (TargetConfigInfo->InterfaceInfoTable == NULL) {
    Status = EFI_OUT_OF_RESOURCES;
    goto Cleanup;
  }

  DEBUG((USB_FUIO_DEBUG_INFO, "[%a] InterfaceInfoTable allocated (%d entries).\n", __FUNCTION__,
    TargetConfigInfo->ConfigDescriptor->NumInterfaces));

  //Copy Interface Table Entries
  Status = EFI_SUCCESS;
  for (UINTN InterfaceIdx = 0; InterfaceIdx < TargetConfigInfo->ConfigDescriptor->NumInterfaces; InterfaceIdx++) {
    //Allocate table entry
    TargetConfigInfo->InterfaceInfoTable[InterfaceIdx] = AllocateZeroPool(sizeof(EFI_USB_SUPERSPEED_INTERFACE_INFO));
    if (TargetConfigInfo->InterfaceInfoTable[InterfaceIdx] == NULL) {
      Status = EFI_OUT_OF_RESOURCES;
      goto Cleanup;
    }

    //Deep-Copy the Interface Descriptor (and sub-structures)
    Status = CopySSInterfaceDescriptor(
      SourceConfigInfo->InterfaceInfoTable[InterfaceIdx],
      TargetConfigInfo->InterfaceInfoTable[InterfaceIdx]
      );

    DEBUG((USB_FUIO_DEBUG_INFO, "[%a] InterfaceInfoTable[%d] allocated and copied.\n", __FUNCTION__, InterfaceIdx));
  }
Cleanup:
  DEBUG((USB_FUIO_DEBUG_INFO, "[%a] done. Status %r\n", __FUNCTION__, Status));
  if (EFI_ERROR(Status)) {
    FreeSSConfigInfo(TargetConfigInfo);
  }
  return Status;
}
/**
  Performs a deep-copy of the Source EFI_USB_DEVICE_INFO structure into the Target EFI_USB_DEVICE_INFO structure.

  1. Allocates and copies the Device Descriptor
  2. Allocates and copies all entries in the ConfigInfoTable.

  @param[in] SourceDeviceInfo   A pointer to EFI_USB_DEVICE_INFO instance to copy  from.
  @param[in] TargetDeviceInfo   A pointer to EFI_USB_DEVICE_INFO instance to copy into.

  @retval - EFI_SUCCESS - copy created successfully.
  @retval - Other - failed to create copy.
**/
EFI_STATUS
CopyDeviceDescriptor(
  IN EFI_USB_DEVICE_INFO *SourceDeviceInfo,
  IN EFI_USB_DEVICE_INFO *TargetDeviceInfo
) {
  EFI_STATUS Status;

  if (SourceDeviceInfo == NULL || TargetDeviceInfo == NULL) {
    return EFI_INVALID_PARAMETER;
  }

  DEBUG((USB_FUIO_DEBUG_INFO, "[%a] Start.\n", __FUNCTION__));

  //Allocate and copy DeviceDescriptor
  TargetDeviceInfo->DeviceDescriptor = AllocateZeroPool(sizeof(EFI_USB_DEVICE_DESCRIPTOR));
  if (TargetDeviceInfo->DeviceDescriptor == NULL) {
    Status = EFI_OUT_OF_RESOURCES;
    goto Cleanup;
  }
  CopyMem(TargetDeviceInfo->DeviceDescriptor, SourceDeviceInfo->DeviceDescriptor, sizeof(EFI_USB_DEVICE_DESCRIPTOR));

  DEBUG((USB_FUIO_DEBUG_INFO, "[%a] DeviceDescriptor allocated and copied.\n", __FUNCTION__));

  //Allocate space for ConfigInfoTable
  TargetDeviceInfo->ConfigInfoTable =
    AllocateZeroPool(sizeof(EFI_USB_CONFIG_INFO*) * TargetDeviceInfo->DeviceDescriptor->NumConfigurations);
  if (TargetDeviceInfo->ConfigInfoTable == NULL) {
    Status = EFI_OUT_OF_RESOURCES;
    goto Cleanup;
  }

  DEBUG((USB_FUIO_DEBUG_INFO, "[%a] ConfigInfoTable allocated (%d entries).\n", __FUNCTION__, 
    TargetDeviceInfo->DeviceDescriptor->NumConfigurations));

  //Copy Config Table Entries
  Status = EFI_SUCCESS;
  for (UINTN ConfigIdx = 0; ConfigIdx < TargetDeviceInfo->DeviceDescriptor->NumConfigurations; ConfigIdx++) {
    //Allocate table entry
    TargetDeviceInfo->ConfigInfoTable[ConfigIdx] = 
      AllocateZeroPool(sizeof(EFI_USB_CONFIG_INFO));
    if (TargetDeviceInfo->ConfigInfoTable[ConfigIdx] == NULL) {
      Status = EFI_OUT_OF_RESOURCES;
      goto Cleanup;
    }

    //Deep-Copy the Config Descriptor (and sub-structures)
    Status = CopyConfigDescriptor(
      SourceDeviceInfo->ConfigInfoTable[ConfigIdx],
      TargetDeviceInfo->ConfigInfoTable[ConfigIdx]);

    DEBUG((USB_FUIO_DEBUG_INFO, "[%a] ConfigInfoTable[%d] allocated and copied.\n", __FUNCTION__, ConfigIdx));
  }

Cleanup:
  DEBUG((USB_FUIO_DEBUG_INFO, "[%a] done. Status %r\n", __FUNCTION__, Status));
  if (EFI_ERROR(Status)) {
      FreeDeviceInfo(TargetDeviceInfo);
  }
  return Status;
}

/**
  Performs a deep-copy of the Source EFI_USB_DEVICE_INFO structure into the Target EFI_USB_DEVICE_INFO structure.

  1. Allocates and copies the Device Descriptor
  2. Allocates and copies all entries in the ConfigInfoTable.

  @param[in] SourceDeviceInfo   A pointer to EFI_USB_DEVICE_INFO instance to copy  from.
  @param[in] TargetDeviceInfo   A pointer to EFI_USB_DEVICE_INFO instance to copy into.

  @retval - EFI_SUCCESS - copy created successfully.
  @retval - Other - failed to create copy.
**/
EFI_STATUS
CopySSDeviceDescriptor(
IN EFI_USB_SUPERSPEED_DEVICE_INFO *SourceDeviceInfo,
IN EFI_USB_SUPERSPEED_DEVICE_INFO *TargetDeviceInfo
) {
  EFI_STATUS Status;

  if (SourceDeviceInfo == NULL || TargetDeviceInfo == NULL) {
    return EFI_INVALID_PARAMETER;
  }

  DEBUG((USB_FUIO_DEBUG_INFO, "[%a] Start.\n", __FUNCTION__));

  //Allocate and copy DeviceDescriptor
  TargetDeviceInfo->DeviceDescriptor = AllocateZeroPool(sizeof(EFI_USB_DEVICE_DESCRIPTOR));
  if (TargetDeviceInfo->DeviceDescriptor == NULL) {
    Status = EFI_OUT_OF_RESOURCES;
    goto Cleanup;
  }
  CopyMem(TargetDeviceInfo->DeviceDescriptor, SourceDeviceInfo->DeviceDescriptor, sizeof(EFI_USB_DEVICE_DESCRIPTOR));

  DEBUG((USB_FUIO_DEBUG_INFO, "[%a] DeviceDescriptor allocated and copied.\n", __FUNCTION__));

  //Allocate space for ConfigInfoTable
  TargetDeviceInfo->ConfigInfoTable =
    AllocateZeroPool(sizeof(EFI_USB_SUPERSPEED_CONFIG_INFO*)* TargetDeviceInfo->DeviceDescriptor->NumConfigurations);
  if (TargetDeviceInfo->ConfigInfoTable == NULL) {
    Status = EFI_OUT_OF_RESOURCES;
    goto Cleanup;
  }

  DEBUG((USB_FUIO_DEBUG_INFO, "[%a] ConfigInfoTable allocated (%d entries).\n", __FUNCTION__,
    TargetDeviceInfo->DeviceDescriptor->NumConfigurations));

  //Copy Config Table Entries
  Status = EFI_SUCCESS;
  for (UINTN ConfigIdx = 0; ConfigIdx < TargetDeviceInfo->DeviceDescriptor->NumConfigurations; ConfigIdx++) {
    //Allocate table entry
    TargetDeviceInfo->ConfigInfoTable[ConfigIdx] =
      AllocateZeroPool(sizeof(EFI_USB_SUPERSPEED_CONFIG_INFO));
    if (TargetDeviceInfo->ConfigInfoTable[ConfigIdx] == NULL) {
      Status = EFI_OUT_OF_RESOURCES;
      goto Cleanup;
    }

    //Deep-Copy the Config Descriptor (and sub-structures)
    Status = CopySSConfigDescriptor(
      SourceDeviceInfo->ConfigInfoTable[ConfigIdx],
      TargetDeviceInfo->ConfigInfoTable[ConfigIdx]);

    DEBUG((USB_FUIO_DEBUG_INFO, "[%a] ConfigInfoTable[%d] allocated and copied.\n", __FUNCTION__, ConfigIdx));
  }

  //Allocate and copy DeviceDescriptor
  TargetDeviceInfo->BosDescriptor = AllocateZeroPool(sizeof(EFI_USB_BOS_DESCRIPTOR));
  if (TargetDeviceInfo->BosDescriptor == NULL) {
    Status = EFI_OUT_OF_RESOURCES;
    goto Cleanup;
  }
  CopyMem(TargetDeviceInfo->BosDescriptor, SourceDeviceInfo->BosDescriptor, sizeof(EFI_USB_BOS_DESCRIPTOR));

  DEBUG((USB_FUIO_DEBUG_INFO, "[%a] BosDescriptor allocated and copied.\n", __FUNCTION__));

Cleanup:
  DEBUG((USB_FUIO_DEBUG_INFO, "[%a] done. Status %r\n", __FUNCTION__, Status));
  if (EFI_ERROR(Status)) {
    FreeSSDeviceInfo(TargetDeviceInfo);
  }
  return Status;
}

/**
  Allocates and returns a new DeviceInfo structure that is a copy of the specified DeviceInfo Structure.

  @param[in] DeviceInfo         A pointer to EFI_USB_DEVICE_INFO instance to copy.
  @param[in] NewDeviceInfo      A pointer to a pointer to EFI_USB_DEVICE_INFO to receive the newly allocated copy.

  @retval - EFI_SUCCESS - copy created successfully.
  @retval - Other - failed to create copy. NewDeviceInfo unmodified.
**/
EFI_STATUS
CopyDeviceInfo(
  IN  EFI_USB_DEVICE_INFO *DeviceInfo,
  OUT EFI_USB_DEVICE_INFO **NewDeviceInfo
)
{
  EFI_STATUS Status;
  EFI_USB_DEVICE_INFO *WorkingDeviceInfo;

  if (DeviceInfo == NULL || NewDeviceInfo == NULL) {
    return EFI_INVALID_PARAMETER;
  }

  DEBUG((USB_FUIO_DEBUG_INFO, "[%a] Start.\n", __FUNCTION__));

  //Allocate space for the new DeviceInfo
  WorkingDeviceInfo = AllocateZeroPool(sizeof (EFI_USB_DEVICE_INFO));
  if (WorkingDeviceInfo == NULL) {
    Status = EFI_OUT_OF_RESOURCES;
    goto Cleanup;
  }

  //Deep-Copy the Device Descriptor (and sub-structures)
  Status = CopyDeviceDescriptor(DeviceInfo, WorkingDeviceInfo);

Cleanup:
  DEBUG((USB_FUIO_DEBUG_INFO, "[%a] done. Status %r\n", __FUNCTION__, Status));
  if (EFI_ERROR(Status)) {
    if (WorkingDeviceInfo != NULL) {
      FreePool(WorkingDeviceInfo);
    }
  } else {
    *NewDeviceInfo = WorkingDeviceInfo;
  }
  return Status;
}

/**
  Allocates and returns a new DeviceInfo structure that is a copy of the specified DeviceInfo Structure.

  @param[in] DeviceInfo         A pointer to EFI_USB_DEVICE_INFO instance to copy.
  @param[in] NewDeviceInfo      A pointer to a pointer to EFI_USB_DEVICE_INFO to receive the newly allocated copy.

  @retval - EFI_SUCCESS - copy created successfully.
  @retval - Other - failed to create copy. NewDeviceInfo unmodified.
**/
EFI_STATUS
CopySSDeviceInfo(
IN  EFI_USB_SUPERSPEED_DEVICE_INFO *DeviceInfo,
OUT EFI_USB_SUPERSPEED_DEVICE_INFO **NewDeviceInfo
)
{
  EFI_STATUS Status;
  EFI_USB_SUPERSPEED_DEVICE_INFO *WorkingDeviceInfo;

  if (DeviceInfo == NULL || NewDeviceInfo == NULL) {
    return EFI_INVALID_PARAMETER;
  }

  DEBUG((USB_FUIO_DEBUG_INFO, "[%a] Start.\n", __FUNCTION__));

  //Allocate space for the new DeviceInfo
  WorkingDeviceInfo = AllocateZeroPool(sizeof (EFI_USB_SUPERSPEED_DEVICE_INFO));
  if (WorkingDeviceInfo == NULL) {
    Status = EFI_OUT_OF_RESOURCES;
    goto Cleanup;
  }

  //Deep-Copy the Device Descriptor (and sub-structures)
  Status = CopySSDeviceDescriptor(DeviceInfo, WorkingDeviceInfo);

Cleanup:
  DEBUG((USB_FUIO_DEBUG_INFO, "[%a] done. Status %r\n", __FUNCTION__, Status));
  if (EFI_ERROR(Status)) {
    if (WorkingDeviceInfo != NULL) {
      FreePool(WorkingDeviceInfo);
    }
  }
  else {
    *NewDeviceInfo = WorkingDeviceInfo;
  }
  return Status;
}

/**
  Configure Super Speed endpoints based on supplied device and configuration descriptors.

  @param[in] This               A pointer to the EFI_USBFN_IO_PROTOCOL instance.
  @param[in] SSDeviceInfo         A pointer to EFI_USB_SUPERSPEED_DEVICE_INFO instance.

  @retval EFI_SUCCESS           The function returned successfully.
  @retval EFI_INVALID_PARAMETER A parameter is invalid.
  @retval EFI_DEVICE_ERROR      The physical device reported an error.
  @retval EFI_NOT_READY         The physical device is busy or not ready to
                                process this request.
  @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to
                                lack of resources.

**/
EFI_STATUS
EFIAPI
ConfigureEnableSSEndpoints (
  IN EFI_USBFN_IO_PROTOCOL           *This,
  IN EFI_USB_SUPERSPEED_DEVICE_INFO  *SSDeviceInfo
  )
{
  EFI_STATUS                        Status;
  USB_XDCI_DEV_CONTEXT              *UsbFuncIoDevPtr;
  EFI_USB_SUPERSPEED_DEVICE_INFO    *TmpDeviceInfo;

  UsbFuncIoDevPtr = USBFUIO_CONTEXT_FROM_PROTOCOL(This);
  Status = EFI_SUCCESS;

  DEBUG((USB_FUIO_DEBUG_LOAD, "ConfigureEnableSSEndpoints - Entry\n"));
  /*
  Assuming that the hardware has already been initialized,
  this function configures the endpoints using supplied
  DeviceInfo, activates the port, and starts receiving USB events
  */
  Status = EFI_SUCCESS;
  if (SSDeviceInfo == NULL) {
    Status = EFI_INVALID_PARAMETER;
    goto FUNC_EXIT;
  }

  DEBUG((USB_FUIO_DEBUG_INFO, "[%a] Starting validation\n", __FUNCTION__));

  //Validate Device Info before allocating new device info.
  if (SSDeviceInfo->DeviceDescriptor->NumConfigurations < 1) {
    DEBUG((DEBUG_ERROR, "[%a] - Warning - DeviceDescriptor->NumConfigurations (%d) < 1\n", __FUNCTION__, SSDeviceInfo->DeviceDescriptor->NumConfigurations));
    Status = EFI_INVALID_PARAMETER;
    goto FUNC_EXIT;
  }
  if (SSDeviceInfo->DeviceDescriptor->NumConfigurations > 1) {
    DEBUG((DEBUG_WARN, "[%a] - Warning - DeviceDescriptor->NumConfigurations (%d) > 1\n", __FUNCTION__, SSDeviceInfo->DeviceDescriptor->NumConfigurations));
  }

  if (SSDeviceInfo->ConfigInfoTable[0]->ConfigDescriptor->NumInterfaces < 1) {
    DEBUG((DEBUG_ERROR, "[%a] - Error - SSDeviceInfo->ConfigInfoTable[0]->ConfigDescriptor->NumInterfaces (%d) < 1\n", __FUNCTION__, SSDeviceInfo->ConfigInfoTable[0]->ConfigDescriptor->NumInterfaces));
    Status = EFI_INVALID_PARAMETER;
    goto FUNC_EXIT;
  }
  if (SSDeviceInfo->ConfigInfoTable[0]->ConfigDescriptor->NumInterfaces > 1) {
    DEBUG((DEBUG_WARN, "[%a] - Warning - SSDeviceInfo->ConfigInfoTable[0]->ConfigDescriptor->NumInterfaces (%d) > 1\n", __FUNCTION__, SSDeviceInfo->ConfigInfoTable[0]->ConfigDescriptor->NumInterfaces));
  }

  if (SSDeviceInfo->ConfigInfoTable[0]->InterfaceInfoTable[0]->InterfaceDescriptor->NumEndpoints < 2) {
    DEBUG((DEBUG_ERROR, "[%a] - Error - SSDeviceInfo->ConfigInfoTable[0]->InterfaceInfoTable[0]->InterfaceDescriptor->NumEndpoints (%d) < 2\n",
      __FUNCTION__, SSDeviceInfo->ConfigInfoTable[0]->InterfaceInfoTable[0]->InterfaceDescriptor->NumEndpoints));
    Status = EFI_INVALID_PARAMETER;
    goto FUNC_EXIT;
  }
  if (SSDeviceInfo->ConfigInfoTable[0]->InterfaceInfoTable[0]->InterfaceDescriptor->NumEndpoints > 2) {
    DEBUG((DEBUG_WARN, "[%a] - Warning - SSDeviceInfo->ConfigInfoTable[0]->InterfaceInfoTable[0]->InterfaceDescriptor->NumEndpoints (%d) > 2\n",
      __FUNCTION__, SSDeviceInfo->ConfigInfoTable[0]->InterfaceInfoTable[0]->InterfaceDescriptor->NumEndpoints));
  }

  DEBUG((USB_FUIO_DEBUG_INFO, "[%a] Device Info Valid\n", __FUNCTION__));

  //
  // Allocate new Device Info and copy provided device info.
  //
  TmpDeviceInfo = NULL;
  Status = CopySSDeviceInfo(SSDeviceInfo, &TmpDeviceInfo);
  if (EFI_ERROR(Status)) {
    DEBUG((USB_FUIO_DEBUG_INFO, "[%a] - Failed to copy SSDeviceInfo: %r\n", __FUNCTION__, Status));
    goto FUNC_EXIT;
  }

  DEBUG((USB_FUIO_DEBUG_INFO, "[%a] Copy SSDeviceInfo succeeded\n", __FUNCTION__));

  //If successful, free the old devinfo (if present), and update it to new dev info
  if (UsbFuncIoDevPtr->SSDevInfoPtr != NULL) {
    FreeSSDeviceInfo(UsbFuncIoDevPtr->SSDevInfoPtr);
    return EFI_SUCCESS;
  }
  UsbFuncIoDevPtr->SSDevInfoPtr = TmpDeviceInfo;

  //
  // Set Configure table
  //
  UsbFuncIoDevPtr->SSIndexPtrConfig.ConfigDescriptor = UsbFuncIoDevPtr->SSDevInfoPtr->ConfigInfoTable[0]->ConfigDescriptor;
  UsbFuncIoDevPtr->SSIndexPtrConfig.InterfaceInfoTable = UsbFuncIoDevPtr->SSDevInfoPtr->ConfigInfoTable[0]->InterfaceInfoTable;

  DEBUG((USB_FUIO_DEBUG_INFO, "[%a] Set Configure table done.\n", __FUNCTION__));

  //
  // Set Interface
  //
  UsbFuncIoDevPtr->SSIndexPtrInteface.InterfaceDescriptor = UsbFuncIoDevPtr->SSDevInfoPtr->ConfigInfoTable[0]->InterfaceInfoTable[0]->InterfaceDescriptor;

  DEBUG((USB_FUIO_DEBUG_INFO, "[%a] Set Interface done.\n", __FUNCTION__));

  //
  // Set Endpoint
  //
  UsbFuncIoDevPtr->IndexPtrInEp.EndpointCompDesc = NULL;
  UsbFuncIoDevPtr->IndexPtrOutEp.EndpointCompDesc = NULL;

  if ((UsbFuncIoDevPtr->SSDevInfoPtr->ConfigInfoTable[0]->InterfaceInfoTable[0]->EndpointDescriptorTable[0]->EndpointDescriptor->EndpointAddress & USB_ENDPOINT_DIR_IN) != 0) {
    UsbFuncIoDevPtr->SSIndexPtrInEp.EndpointDesc = UsbFuncIoDevPtr->SSDevInfoPtr->ConfigInfoTable[0]->InterfaceInfoTable[0]->EndpointDescriptorTable[0]->EndpointDescriptor;
    UsbFuncIoDevPtr->SSIndexPtrOutEp.EndpointDesc = UsbFuncIoDevPtr->SSDevInfoPtr->ConfigInfoTable[0]->InterfaceInfoTable[0]->EndpointDescriptorTable[1]->EndpointDescriptor;
  }
  else {
    UsbFuncIoDevPtr->SSIndexPtrInEp.EndpointDesc = UsbFuncIoDevPtr->SSDevInfoPtr->ConfigInfoTable[0]->InterfaceInfoTable[0]->EndpointDescriptorTable[1]->EndpointDescriptor;
    UsbFuncIoDevPtr->SSIndexPtrOutEp.EndpointDesc = UsbFuncIoDevPtr->SSDevInfoPtr->ConfigInfoTable[0]->InterfaceInfoTable[0]->EndpointDescriptorTable[0]->EndpointDescriptor;
  }

  DEBUG((USB_FUIO_DEBUG_INFO, "[%a] Set Endpoint done.\n", __FUNCTION__));

  DEBUG((USB_FUIO_DEBUG_LOAD, " In Ep Num 0x%02x\n", UsbFuncIoDevPtr->SSIndexPtrInEp.EndpointDesc->EndpointAddress));

  DEBUG((USB_FUIO_DEBUG_LOAD, " Out Ep Num 0x%02x\n", UsbFuncIoDevPtr->SSIndexPtrOutEp.EndpointDesc->EndpointAddress));

FUNC_EXIT:
  DEBUG((USB_FUIO_DEBUG_LOAD, "ConfigureEnableEndpoints - exit %r\n", Status));
  return Status;
}
/**
  Configure endpoints based on supplied device and configuration descriptors.

  @param[in] This               A pointer to the EFI_USBFN_IO_PROTOCOL instance.
  @param[in] DeviceInfo         A pointer to EFI_USBFN_DEVICE_INFO instance.

  @retval EFI_SUCCESS           The function returned successfully.
  @retval EFI_INVALID_PARAMETER A parameter is invalid.
  @retval EFI_DEVICE_ERROR      The physical device reported an error.
  @retval EFI_NOT_READY         The physical device is busy or not ready to
                                process this request.
  @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to
                                lack of resources.

**/
EFI_STATUS
EFIAPI
ConfigureEnableEndpoints (
  IN EFI_USBFN_IO_PROTOCOL         *This,
  IN EFI_USB_DEVICE_INFO           *DeviceInfo
  )
{
  EFI_STATUS                        Status;
  USB_XDCI_DEV_CONTEXT              *UsbFuncIoDevPtr;
  EFI_USB_DEVICE_INFO               *TmpDeviceInfo;

  UsbFuncIoDevPtr = USBFUIO_CONTEXT_FROM_PROTOCOL (This);
  Status = EFI_SUCCESS;

  DEBUG ((USB_FUIO_DEBUG_LOAD, "ConfigureEnableEndpoints - Entry\n"));
  /*
  Assuming that the hardware has already been initialized,
  this function configures the endpoints using supplied
  DeviceInfo, activates the port, and starts receiving USB events
  */
  Status = EFI_SUCCESS;
  if (DeviceInfo == NULL) {
    Status = EFI_INVALID_PARAMETER;
    goto FUNC_EXIT;
  }

  DEBUG((USB_FUIO_DEBUG_INFO, "[%a] Starting validation\n", __FUNCTION__));

  //Validate Device Info before allocating new device info.
  if (DeviceInfo->DeviceDescriptor->NumConfigurations < 1) {
    DEBUG ((DEBUG_ERROR, "[%a] - Warning - DeviceDescriptor->NumConfigurations (%d) < 1\n", __FUNCTION__, DeviceInfo->DeviceDescriptor->NumConfigurations));
    Status = EFI_INVALID_PARAMETER;
    goto FUNC_EXIT;
  }
  if (DeviceInfo->DeviceDescriptor->NumConfigurations > 1) {
    DEBUG ((DEBUG_WARN, "[%a] - Warning - DeviceDescriptor->NumConfigurations (%d) > 1\n", __FUNCTION__, DeviceInfo->DeviceDescriptor->NumConfigurations));
  }

  if (DeviceInfo->ConfigInfoTable[0]->ConfigDescriptor->NumInterfaces < 1) {
    DEBUG ((DEBUG_ERROR, "[%a] - Error - DeviceInfo->ConfigInfoTable[0]->ConfigDescriptor->NumInterfaces (%d) < 1\n", __FUNCTION__, DeviceInfo->ConfigInfoTable[0]->ConfigDescriptor->NumInterfaces));
    Status = EFI_INVALID_PARAMETER;
    goto FUNC_EXIT;
  }
  if (DeviceInfo->ConfigInfoTable[0]->ConfigDescriptor->NumInterfaces > 1) {
    DEBUG ((DEBUG_WARN, "[%a] - Warning - DeviceInfo->ConfigInfoTable[0]->ConfigDescriptor->NumInterfaces (%d) > 1\n", __FUNCTION__, DeviceInfo->ConfigInfoTable[0]->ConfigDescriptor->NumInterfaces));
  }

  if (DeviceInfo->ConfigInfoTable[0]->InterfaceInfoTable[0]->InterfaceDescriptor->NumEndpoints < 2) {
    DEBUG ((DEBUG_ERROR, "[%a] - Error - DeviceInfo->ConfigInfoTable[0]->InterfaceInfoTable[0]->InterfaceDescriptor->NumEndpoints (%d) < 2\n",
      __FUNCTION__, DeviceInfo->ConfigInfoTable[0]->InterfaceInfoTable[0]->InterfaceDescriptor->NumEndpoints));
      Status = EFI_INVALID_PARAMETER;
      goto FUNC_EXIT;
  }
  if (DeviceInfo->ConfigInfoTable[0]->InterfaceInfoTable[0]->InterfaceDescriptor->NumEndpoints > 2) {
    DEBUG ((DEBUG_WARN, "[%a] - Warning - DeviceInfo->ConfigInfoTable[0]->InterfaceInfoTable[0]->InterfaceDescriptor->NumEndpoints (%d) > 2\n",
      __FUNCTION__, DeviceInfo->ConfigInfoTable[0]->InterfaceInfoTable[0]->InterfaceDescriptor->NumEndpoints));
  }

  DEBUG((USB_FUIO_DEBUG_INFO, "[%a] Device Info Valid\n", __FUNCTION__));

  //
  // Allocate new Device Info and copy provided device info.
  //
  TmpDeviceInfo = NULL;
  Status = CopyDeviceInfo(DeviceInfo, &TmpDeviceInfo);
  if (EFI_ERROR(Status)) {
    DEBUG((USB_FUIO_DEBUG_INFO, "[%a] - Failed to copy DeviceInfo: %r\n", __FUNCTION__, Status));
    goto FUNC_EXIT;
  }

  DEBUG((USB_FUIO_DEBUG_INFO, "[%a] Copy DeviceInfo succeeded\n", __FUNCTION__));

  //If successful, free the old devinfo (if present), and update it to new dev info
  if (UsbFuncIoDevPtr->DevInfoPtr != NULL) {
    FreeDeviceInfo(UsbFuncIoDevPtr->DevInfoPtr);
  }
  UsbFuncIoDevPtr->DevInfoPtr = TmpDeviceInfo;

  //
  // Set Configure table
  //
  UsbFuncIoDevPtr->IndexPtrConfig.ConfigDescriptor = UsbFuncIoDevPtr->DevInfoPtr->ConfigInfoTable[0]->ConfigDescriptor;
  UsbFuncIoDevPtr->IndexPtrConfig.InterfaceInfoTable = UsbFuncIoDevPtr->DevInfoPtr->ConfigInfoTable[0]->InterfaceInfoTable;

  DEBUG((USB_FUIO_DEBUG_INFO, "[%a] Set Configure table done.\n", __FUNCTION__));

  //
  // Set Interface
  //
  UsbFuncIoDevPtr->IndexPtrInteface.InterfaceDescriptor = UsbFuncIoDevPtr->DevInfoPtr->ConfigInfoTable[0]->InterfaceInfoTable[0]->InterfaceDescriptor;

  DEBUG((USB_FUIO_DEBUG_INFO, "[%a] Set Interface done.\n", __FUNCTION__));

  //
  // Set Endpoint
  //
  UsbFuncIoDevPtr->IndexPtrInEp.EndpointCompDesc = NULL;
  UsbFuncIoDevPtr->IndexPtrOutEp.EndpointCompDesc = NULL;

  if ((UsbFuncIoDevPtr->DevInfoPtr->ConfigInfoTable[0]->InterfaceInfoTable[0]->EndpointDescriptorTable[0]->EndpointAddress & USB_ENDPOINT_DIR_IN) != 0) {
    UsbFuncIoDevPtr->IndexPtrInEp.EndpointDesc = UsbFuncIoDevPtr->DevInfoPtr->ConfigInfoTable[0]->InterfaceInfoTable[0]->EndpointDescriptorTable[0];
    UsbFuncIoDevPtr->IndexPtrOutEp.EndpointDesc = UsbFuncIoDevPtr->DevInfoPtr->ConfigInfoTable[0]->InterfaceInfoTable[0]->EndpointDescriptorTable[1];
  } else {
    UsbFuncIoDevPtr->IndexPtrInEp.EndpointDesc = UsbFuncIoDevPtr->DevInfoPtr->ConfigInfoTable[0]->InterfaceInfoTable[0]->EndpointDescriptorTable[1];
    UsbFuncIoDevPtr->IndexPtrOutEp.EndpointDesc = UsbFuncIoDevPtr->DevInfoPtr->ConfigInfoTable[0]->InterfaceInfoTable[0]->EndpointDescriptorTable[0];
  }

    DEBUG((USB_FUIO_DEBUG_INFO, "[%a] Set Endpoint done.\n", __FUNCTION__));

  DEBUG ((USB_FUIO_DEBUG_LOAD, " In Ep Num 0x%02x\n", UsbFuncIoDevPtr->IndexPtrInEp.EndpointDesc->EndpointAddress));

  DEBUG ((USB_FUIO_DEBUG_LOAD, " Out Ep Num 0x%02x\n", UsbFuncIoDevPtr->IndexPtrOutEp.EndpointDesc->EndpointAddress));

FUNC_EXIT:
  DEBUG ((USB_FUIO_DEBUG_LOAD, "ConfigureEnableEndpoints - exit %r\n", Status));
  return Status;
}

/**
  Returns the maximum packet size of the specified endpoint type for
  the supplied bus speed.

  @param[in] This               A pointer to the EFI_USBFN_IO_PROTOCOL instance.
  @param[in] EndpointType       Endpoint type as defined as EFI_USB_ENDPOINT_TYPE.
  @param[in] BusSpeed           Bus speed as defined as EFI_USB_BUS_SPEED.
  @param[in] MaxPacketSize      The maximum packet size, in bytes,
                                of the specified endpoint type.

  @retval EFI_SUCCESS           The function returned successfully.
  @retval EFI_INVALID_PARAMETER A parameter is invalid.
  @retval EFI_DEVICE_ERROR      The physical device reported an error.
  @retval EFI_NOT_READY         The physical device is busy or not ready to
                                process this request.
**/
EFI_STATUS
EFIAPI
GetEndpointMaxPacketSize (
  IN EFI_USBFN_IO_PROTOCOL      *This,
  IN EFI_USB_ENDPOINT_TYPE      EndpointType,
  IN EFI_USB_BUS_SPEED          BusSpeed,
  OUT UINT16                    *MaxPacketSize
  )
{
  EFI_STATUS                        Status;
  USB_XDCI_DEV_CONTEXT              *UsbFuncIoDevPtr;
  USB_DEV_CORE                      *DevCorePtr;
  XDCI_CORE_HANDLE                  *XdciCorePtr;

  UsbFuncIoDevPtr = USBFUIO_CONTEXT_FROM_PROTOCOL (This);
  DevCorePtr = UsbFuncIoDevPtr->DrvCore;
  XdciCorePtr = DevCorePtr->controller_handle;
  Status = EFI_SUCCESS;

  DEBUG ((USB_FUIO_DEBUG_LOAD, "GetEndpointMaxPacketSize - Entry\n"));

  switch (EndpointType) {
    case UsbEndpointControl:
      //*MaxPacketSize = USB_EP0_MAX_PKT_SIZE_HS;
#ifdef SUPPORT_SUPER_SPEED
      *MaxPacketSize = USB_EP0_MAX_PKT_SIZE_SS; // Default to super speed
#else
      *MaxPacketSize = USB_EP0_MAX_PKT_SIZE_HS; // Default to high speed
#endif
      break;

    case UsbEndpointBulk:
#ifdef SUPPORT_SUPER_SPEED
      *MaxPacketSize = USB_BULK_EP_PKT_SIZE_SS; // Default to super speed
#else
      *MaxPacketSize = USB_BULK_EP_PKT_SIZE_HS; // Default to high speed
#endif
      break;

    case UsbEndpointInterrupt:
      *MaxPacketSize = 1;
      break;

    case UsbEndpointIsochronous:
    default:
      Status = EFI_DEVICE_ERROR;
      break;
  }

  DEBUG ((USB_FUIO_DEBUG_LOAD, "GetEndpointMaxPacketSize - Exit %r\n", Status));
  return Status;
}


/**
  Returns the maximum supported transfer size.

  @param[in] This               A pointer to the EFI_USBFN_IO_PROTOCOL instance.
  @param[in] MaxTransferSize    The maximum supported transfer size, in bytes.

  @retval EFI_SUCCESS           The function returned successfully.
  @retval EFI_INVALID_PARAMETER A parameter is invalid.
  @retval EFI_DEVICE_ERROR      The physical device reported an error.
  @retval EFI_NOT_READY         The physical device is busy or not ready to
                                process this request.
**/
EFI_STATUS
EFIAPI
GetMaxTransferSize (
  IN EFI_USBFN_IO_PROTOCOL     *This,
  OUT UINTN                    *MaxTransferSize
  )
{
//#ifdef SUPPORT_SUPER_SPEED
//  *MaxTransferSize = USB_BULK_EP_PKT_SIZE_SS;
//#else
//  *MaxTransferSize = USB_BULK_EP_PKT_SIZE_HS;
//#endif

  //
  // Need to check, Make max transfer package to 8MB
  //
  *MaxTransferSize = MAX_TRANSFER_PACKET;
  return EFI_SUCCESS;
}


/**
  This function returns the unique device ID of the device--this matches
  what is populated in the SMBIOS table.

  @param[in/out] BufferSize     On input, the size of the Buffer in bytes.
                                On output, the amount of data returned in Buffer
                                in bytes.

  @param[out] Buffer            A pointer to a buffer to return the requested
                                information as a Unicode string. What string are
                                we talking about

  @retval EFI_SUCCESS           The function returned successfully.
  @retval EFI_BUFFER_TOO_SMALL  A parameter is invalid.

**/
STATIC
EFI_STATUS
EFIAPI
GetDeviceSerialNumber (
    IN OUT UINTN *BufferSize,
    OUT VOID *Buffer OPTIONAL
  )
{
    EFI_STATUS Status = EFI_SUCCESS;
    CHAR16 UuidString[CHARS_IN_GUID];
    UINTN CharsCopied;

    DEBUG ((USB_FUIO_DEBUG_LOAD, "+GetDeviceSerialNumber\n"));

    /* check bounds */
    if (*BufferSize < sizeof(UuidString)) {
      DEBUG((USB_FUIO_DEBUG_LOAD, "+GetDeviceSerialNumber 1\n"));
        Status = EFI_BUFFER_TOO_SMALL;
        *BufferSize = 0;
        goto Error;
    }

    /* Data1 will get the product serial number (populated from the eMMC) */
    //mSmBiosUniqueGuid.Data1 = PcdGet32(PcdProductSerialNumber);

    /* Data4[0] will contain the manufacturer ID (populated from the eMMC) */
    //mSmBiosUniqueGuid.Data4[0] = PcdGet8(PcdEmmcManufacturerId);

    /**
     * The rest of mSmBiosUniqueGuid will be same. Note that we cannot
     * read the SMBIOS table directly, as it might not be ready by the time we
     * are to read it. The population of the data from the eMMC is ready
     * by the time we are here.
     */

    /* Print to to a string, and copy it off */
    CharsCopied = UnicodeSPrint(UuidString, sizeof(UuidString), L"%g", &mSmBiosUniqueGuid);
    if (CharsCopied != (CHARS_IN_GUID - 1))
    {
      DEBUG((USB_FUIO_DEBUG_LOAD, "+GetDeviceSerialNumber 2\n"));
        Status = EFI_BUFFER_TOO_SMALL;
        *BufferSize = 0;
        goto Error;
    }
    CopyMem(Buffer, UuidString, sizeof(UuidString));
    *BufferSize = sizeof(UuidString);

Error:

    DEBUG ((USB_FUIO_DEBUG_LOAD, "-GetDeviceSerialNumber, Status = 0x%08x\r\n", Status));

    return Status;
}


/**
  Returns device specific information based on the supplied identifier as
  a Unicode string

  @param[in] This               A pointer to the EFI_USBFN_IO_PROTOCOL instance.
  @param[in] Id                 Requested information id.
  @param[in] BufferSize         On input, the size of the Buffer in bytes.
                                On output, the amount of data returned in Buffer
                                in bytes.
  @param[in] Buffer             A pointer to a buffer to return the requested
                                information as a Unicode string.

  @retval EFI_SUCCESS           The function returned successfully.
  @retval EFI_INVALID_PARAMETER A parameter is invalid.
  @retval EFI_DEVICE_ERROR      The physical device reported an error.
  @retval EFI_NOT_READY         The physical device is busy or not ready to
                                process this request.
**/
EFI_STATUS
EFIAPI
GetDeviceInfo (
  IN EFI_USBFN_IO_PROTOCOL      *This,
  IN EFI_USBFN_DEVICE_INFO_ID   Id,
  IN OUT UINTN                  *BufferSize,
  OUT VOID                      *Buffer OPTIONAL
  )
{
  EFI_STATUS                    Status;
  USB_XDCI_DEV_CONTEXT          *UsbFuncIoDevPtr;

  UsbFuncIoDevPtr = USBFUIO_CONTEXT_FROM_PROTOCOL (This);
  Status = EFI_SUCCESS;

  DEBUG ((USB_FUIO_DEBUG_LOAD, "GetDeviceInfo - Entry\n"));

  if ((BufferSize == 0) || (Buffer == NULL)) {
    Status = EFI_INVALID_PARAMETER;
    goto FUN_EXIT;
  }

  switch (Id) {

    case EfiUsbDeviceInfoSerialNumber:
        Status = GetDeviceSerialNumber(BufferSize, Buffer);
        if (!EFI_ERROR(Status))
        {
            goto FUN_EXIT;
        }
        break;

    case EfiUsbDeviceInfoManufacturerName:
        if (*BufferSize < sizeof(mUsbFnDxeMfgString)) {
            Status = EFI_BUFFER_TOO_SMALL;
            *BufferSize = 0;
            goto FUN_EXIT;
        }
        CopyMem(Buffer, mUsbFnDxeMfgString, sizeof(mUsbFnDxeMfgString));
        *BufferSize = sizeof(mUsbFnDxeMfgString);
        break;

    case EfiUsbDeviceInfoProductName:
        if (*BufferSize < sizeof(mUsbFnDxeProductString)) {
            Status = EFI_BUFFER_TOO_SMALL;
            *BufferSize = 0;
            goto FUN_EXIT;
        }
        CopyMem(Buffer, mUsbFnDxeProductString, sizeof(mUsbFnDxeProductString));
        *BufferSize = sizeof(mUsbFnDxeProductString);
        break;

    case EfiUsbDeviceInfoUnknown:
    default:
      Status = EFI_UNSUPPORTED;
      *BufferSize = 0;
      DEBUG ((USB_FUIO_DEBUG_ERROR, "Unknown ID %d encountered.\r\n", Id));
      break;
  }

FUN_EXIT:
  DEBUG ((USB_FUIO_DEBUG_LOAD, "GetDeviceInfo - ConfigDescriptor addr 0x%08x \n", (UINTN)UsbFuncIoDevPtr->IndexPtrConfig.ConfigDescriptor));
  DEBUG ((USB_FUIO_DEBUG_LOAD, "GetDeviceInfo - Exit %r\n", Status));
  return Status;
}


/**
  Returns vendor-id and product-id of the device.

  @param[in]  This              A pointer to the EFI_USBFN_IO_PROTOCOL instance.
  @param[out] Vid               Returned vendor-id of the device.
  @param[out] Pid               Returned product-id of the device.

  @retval EFI_SUCCESS           The function returned successfully.
  @retval EFI_INVALID_PARAMETER A parameter is invalid.
  @retval EFI_NOT_FOUND         Unable to return vid or pid.

**/
EFI_STATUS
EFIAPI
GetVendorIdProductId (
  IN EFI_USBFN_IO_PROTOCOL      *This,
  OUT UINT16                    *Vid,
  OUT UINT16                    *Pid
  )
{
  USB_XDCI_DEV_CONTEXT              *UsbFuncIoDevPtr;

  UsbFuncIoDevPtr = USBFUIO_CONTEXT_FROM_PROTOCOL (This);
  //   *Vid = 0x8086;
  //   *Pid = 0x0A65
  *Vid = UsbFuncIoDevPtr->VendorId;
  *Pid = UsbFuncIoDevPtr->DeviceId;
  return EFI_SUCCESS;
}

/**
  Aborts transfer on the specified endpoint.

  @param[in]  This              A pointer to the EFI_USBFN_IO_PROTOCOL instance.
  @param[in]  EndpointIndex     Indicates the endpoint on which the ongoing
                                transfer needs to be canceled.
  @param[in]  Direction         Direction of the endpoint.


  @retval EFI_SUCCESS           The function returned successfully.
  @retval EFI_INVALID_PARAMETER A parameter is invalid.
  @retval EFI_DEVICE_ERROR      The physical device reported an error.
  @retval EFI_NOT_READY         The physical device is busy or not ready to
                                process this request.

**/
EFI_STATUS
EFIAPI
AbortTransfer (
  IN EFI_USBFN_IO_PROTOCOL        *This,
  IN UINT8                        EndpointIndex,
  IN EFI_USBFN_ENDPOINT_DIRECTION Direction
  )
{
  USB_XDCI_DEV_CONTEXT              *UsbFuncIoDevPtr;
  XDCI_CORE_HANDLE                  *XdciCorePtr;
  USB_DEV_CORE                      *UsbDeviceCorePtr;
  USB_EP_INFO                       EpInfo;
  EFI_STATUS                        Status;

  DEBUG ((USB_FUIO_DEBUG_LOAD, "FU:AbortTransfer EP 0x%02x- Direction %d __Entry\n", EndpointIndex, Direction));
  UsbFuncIoDevPtr = USBFUIO_CONTEXT_FROM_PROTOCOL (This);
  UsbDeviceCorePtr = UsbFuncIoDevPtr->DrvCore;
  XdciCorePtr = UsbDeviceCorePtr->controller_handle;
  Status = EFI_SUCCESS;

  if (UsbFuncIoDevPtr->DevResetFlag == TRUE) {
    return Status;
  }

  EpInfo.ep_num = EndpointIndex;
  EpInfo.ep_dir = Direction? UsbEpDirIn : UsbEpDirOut;

  Status = usb_device_ep_cancel_transfer (UsbFuncIoDevPtr->DrvCore, &EpInfo);
  if (EndpointIndex == 0x00 && Direction == UsbEpDirOut) {
    SetEndpointStallState(This,EndpointIndex,Direction,TRUE);
  }

  DEBUG ((USB_FUIO_DEBUG_LOAD, "FU:AbortTransfer - Exit %r\n", Status));
  return Status;
}

/**
  Returns the stall state on the specified endpoint.

  @param[in]  This              A pointer to the EFI_USBFN_IO_PROTOCOL instance.
  @param[in]  EndpointIndex     Indicates the endpoint on which the ongoing
                                transfer needs to be canceled.
  @param[in]  Direction         Direction of the endpoint.
  @param[in]  State             Boolean, true value indicates that the endpoint
                                is in a stalled state, false otherwise.

  @retval EFI_SUCCESS           The function returned successfully.
  @retval EFI_INVALID_PARAMETER A parameter is invalid.
  @retval EFI_DEVICE_ERROR      The physical device reported an error.
  @retval EFI_NOT_READY         The physical device is busy or not ready to
                                process this request.

**/
EFI_STATUS
EFIAPI
GetEndpointStallState (
  IN EFI_USBFN_IO_PROTOCOL        *This,
  IN UINT8                        EndpointIndex,
  IN EFI_USBFN_ENDPOINT_DIRECTION Direction,
  IN OUT BOOLEAN                  *State
  )
{
  USB_XDCI_DEV_CONTEXT              *UsbFuncIoDevPtr;
  XDCI_CORE_HANDLE                  *XdciCorePtr;
  UINT32                            EndPoint;

  UsbFuncIoDevPtr = USBFUIO_CONTEXT_FROM_PROTOCOL (This);
  DEBUG ((USB_FUIO_DEBUG_LOAD, "GetEndpointStallState - Entry\n"));

  EndPoint = usb_get_physical_ep_num (EndpointIndex, Direction ? UsbEpDirIn : UsbEpDirOut);

  XdciCorePtr = UsbFuncIoDevPtr->XdciDrvIfHandle;

  if (XdciCorePtr->ep_handles[EndPoint].state == USB_EP_STATE_STALLED) {
    *State = TRUE;
  } else {
    *State = FALSE;
  }

  DEBUG ((USB_FUIO_DEBUG_LOAD, "GetEndpointStallState - Exit\n"));
  return EFI_SUCCESS;
}


EFI_STATUS
UsbSetAddress (
  IN EFI_USBFN_IO_PROTOCOL        *This,
  IN UINT32                        Address
  )
{
  EFI_STATUS                        Status;
  USB_XDCI_DEV_CONTEXT              *UsbFuncIoDevPtr;
  XDCI_CORE_HANDLE                  *XdciCorePtr;
  USB_DEV_CORE                      *UsbDeviceCorePtr;

  DEBUG ((USB_FUIO_DEBUG_LOAD, "UsbSetAddress - 0x%04x Entry\n", Address));

  UsbFuncIoDevPtr = USBFUIO_CONTEXT_FROM_PROTOCOL (This);

  UsbDeviceCorePtr = UsbFuncIoDevPtr->DrvCore;
  XdciCorePtr = UsbDeviceCorePtr->controller_handle;
  Status = EFI_SUCCESS;

  Status = usb_device_set_address (UsbDeviceCorePtr, (UINT32)Address);

  if (Status != EFI_SUCCESS) {
    Status = EFI_DEVICE_ERROR;
    goto EXIT_SET_ADDRESS;
  }

  Status = usb_device_ep0_tx_status (UsbDeviceCorePtr);

  if (Status != EFI_SUCCESS) {
    Status = EFI_NO_RESPONSE;
    goto EXIT_SET_ADDRESS;
  }

EXIT_SET_ADDRESS:

  DEBUG ((USB_FUIO_DEBUG_LOAD, "UsbSetAddress - Exit %r\n", Status));
  return Status;
}


EFI_STATUS
EFIAPI
UsbSetconfigure (
  IN EFI_USBFN_IO_PROTOCOL        *This,
  IN UINT32                       InterFaceIndex
  )
{
  EFI_STATUS                         Status;
  USB_XDCI_DEV_CONTEXT               *UsbFuncIoDevPtr;
  XDCI_CORE_HANDLE                   *XdciCorePtr;
  USB_DEV_CORE                       *UsbDeviceCorePtr;
  UINT32                             InterfaceNum;
  UINT32                             EndPointNum;
  UINT32                             EndPointIndex;
  EFI_USB_INTERFACE_INFO             *InterfaceInfoPtr;
  EFI_USB_SUPERSPEED_INTERFACE_INFO  *SSInterfaceInfoPtr;
  USB_EP_INFO                        EpInfo;
  USB_DEVICE_ENDPOINT_INFO           EpDescInfo;

  DEBUG ((USB_FUIO_DEBUG_LOAD, "UsbSetconfigure - 0x%04x Entry\n", InterFaceIndex));

  UsbFuncIoDevPtr = USBFUIO_CONTEXT_FROM_PROTOCOL (This);
  UsbDeviceCorePtr = UsbFuncIoDevPtr->DrvCore;
  XdciCorePtr = UsbDeviceCorePtr->controller_handle;
  Status = EFI_SUCCESS;
  if (UsbFuncIoDevPtr->XdciDrvIfHandle->actual_speed == USB_SPEED_SUPER) {
    InterfaceNum = UsbFuncIoDevPtr->SSIndexPtrConfig.ConfigDescriptor->NumInterfaces;
    DEBUG((USB_FUIO_DEBUG_LOAD, "UsbSetconfigure - ConfigDescriptor addr 0x%08x \n", (UINTN)UsbFuncIoDevPtr->SSIndexPtrConfig.ConfigDescriptor));

    DEBUG((USB_FUIO_DEBUG_LOAD, "UsbSetconfigure - DescriptorType 0x%04x ; ConfigurationValue 0x%04x\n",
           UsbFuncIoDevPtr->SSIndexPtrConfig.ConfigDescriptor->DescriptorType,
           UsbFuncIoDevPtr->SSIndexPtrConfig.ConfigDescriptor->ConfigurationValue
           ));
  } else {
    InterfaceNum = UsbFuncIoDevPtr->IndexPtrConfig.ConfigDescriptor->NumInterfaces;
    DEBUG ((USB_FUIO_DEBUG_LOAD, "UsbSetconfigure - ConfigDescriptor addr 0x%08x \n", (UINTN)UsbFuncIoDevPtr->IndexPtrConfig.ConfigDescriptor));

    DEBUG ((USB_FUIO_DEBUG_LOAD, "UsbSetconfigure - DescriptorType 0x%04x ; ConfigurationValue 0x%04x\n",
            UsbFuncIoDevPtr->IndexPtrConfig.ConfigDescriptor->DescriptorType,
            UsbFuncIoDevPtr->IndexPtrConfig.ConfigDescriptor->ConfigurationValue
            ));
  }

  DEBUG ((USB_FUIO_DEBUG_LOAD, "UsbSetconfigure - InterfaceNum 0x%04x \n", InterfaceNum));
  if (InterfaceNum < InterFaceIndex) {
    Status = EFI_INVALID_PARAMETER;
    goto EXIT__SET_CONFIGURE;
  }

  //
  // Arry strart form '0', Index start from '1'.
  //
  if (UsbFuncIoDevPtr->XdciDrvIfHandle->actual_speed == USB_SPEED_SUPER) {
    SSInterfaceInfoPtr = UsbFuncIoDevPtr->SSIndexPtrConfig.InterfaceInfoTable[InterFaceIndex - 1];
    EndPointNum = SSInterfaceInfoPtr->InterfaceDescriptor->NumEndpoints;
  } else {
    InterfaceInfoPtr = UsbFuncIoDevPtr->IndexPtrConfig.InterfaceInfoTable[InterFaceIndex - 1];
    EndPointNum = InterfaceInfoPtr->InterfaceDescriptor->NumEndpoints;
  }

  DEBUG ((USB_FUIO_DEBUG_LOAD, "UsbSetconfigure - Total EP NUM 0x%04x \n", EndPointNum));

  for (EndPointIndex = 0; EndPointIndex < EndPointNum; EndPointIndex++) {
    if (UsbFuncIoDevPtr->XdciDrvIfHandle->actual_speed == USB_SPEED_SUPER) {
      EpDescInfo.EndpointDesc = SSInterfaceInfoPtr->EndpointDescriptorTable[EndPointIndex]->EndpointDescriptor;
      EpDescInfo.EndpointCompDesc = (EFI_USB_ENDPOINT_COMPANION_DESCRIPTOR *) SSInterfaceInfoPtr->EndpointDescriptorTable[EndPointIndex]->EndpointCompanionDescriptor;
    } else {
      EpDescInfo.EndpointDesc = InterfaceInfoPtr->EndpointDescriptorTable[EndPointIndex];
      EpDescInfo.EndpointCompDesc = NULL;
    }
    UsbFnSetEpInfo (&EpInfo, &EpDescInfo);
    DEBUG ((USB_FUIO_DEBUG_LOAD, "EndpointAddress 0x%02x\n", EpDescInfo.EndpointDesc->EndpointAddress));

    if (usb_device_init_ep (UsbDeviceCorePtr, &EpInfo) == EFI_SUCCESS) {
       if (usb_device_ep_enable (UsbDeviceCorePtr, &EpInfo) == EFI_SUCCESS) {
       } else {
         Status = EFI_DEVICE_ERROR;
         DEBUG ((DEBUG_INFO, "usb_device_ep_enable() - Failed to enable endpoint\n"));
       }
    } else {
       Status = EFI_DEVICE_ERROR;
       DEBUG ((DEBUG_INFO, "usb_device_init_ep() - Failed to initialize endpoint\n"));
    }
  }
  if (UsbFuncIoDevPtr->XdciDrvIfHandle->actual_speed != USB_SPEED_SUPER) {
    Status = usb_device_ep0_tx_status (UsbDeviceCorePtr);
  }
  if (Status != EFI_SUCCESS) {
    Status = EFI_NO_RESPONSE;
    goto EXIT__SET_CONFIGURE;
  }


EXIT__SET_CONFIGURE:
  DEBUG ((USB_FUIO_DEBUG_LOAD, "UsbSetconfigure - Exit %r\n", Status));

  return Status;
}

/**
  Sets or clears the stall state on the specified endpoint.

  @param[in]  This              A pointer to the EFI_USBFN_IO_PROTOCOL instance.
  @param[in]  EndpointIndex     Indicates the endpoint on which the ongoing
                                transfer needs to be canceled.
  @param[in]  Direction         Direction of the endpoint.
  @param[in]  State             Requested stall state on the specified endpoint.
                                True value causes the endpoint to stall;
                                false value clears an existing stall.

  @retval EFI_SUCCESS           The function returned successfully.
  @retval EFI_INVALID_PARAMETER A parameter is invalid.
  @retval EFI_DEVICE_ERROR      The physical device reported an error.
  @retval EFI_NOT_READY         The physical device is busy or not ready to
                                process this request.

**/
EFI_STATUS
EFIAPI
SetEndpointStallState (
  IN EFI_USBFN_IO_PROTOCOL        *This,
  IN UINT8                        EndpointIndex,
  IN EFI_USBFN_ENDPOINT_DIRECTION Direction,
  IN BOOLEAN                      State
  )
{
  EFI_STATUS                        Status;
  USB_XDCI_DEV_CONTEXT              *UsbFuncIoDevPtr;
  USB_EP_INFO                       pEpInfo;

  UsbFuncIoDevPtr = USBFUIO_CONTEXT_FROM_PROTOCOL (This);

  DEBUG ((USB_FUIO_DEBUG_LOAD, "SetEndpointStallState - Entry\n"));
  Status = EFI_SUCCESS;

  pEpInfo.ep_num = EndpointIndex;
  pEpInfo.ep_dir = Direction? UsbEpDirIn : UsbEpDirOut;

  if (State == TRUE) {
    Status = usb_device_ep_stall (UsbFuncIoDevPtr->DrvCore, (VOID*)(UINTN) &pEpInfo);
  } else {
    Status = usb_device_ep_clear_stall (UsbFuncIoDevPtr->DrvCore, (VOID*)(UINTN) &pEpInfo);
  }

  if (Status != EFI_SUCCESS) {
    Status = EFI_DEVICE_ERROR;
  }

  DEBUG ((USB_FUIO_DEBUG_LOAD, "SetEndpointStallState - Exit\n"));
  return Status;
}

EFI_STATUS
DeviceEventCheck(
  IN  EFI_USBFN_IO_PROTOCOL       *This,
  IN  USBD_EVENT_BUF              *EventIndex,
  OUT UINT32                      *ProcessSize,
  OUT EFI_USBFN_MESSAGE           *Message,
  IN OUT UINTN                    *PayloadSize,
  OUT EFI_USBFN_MESSAGE_PAYLOAD   *Payload,
  OUT BOOLEAN                     *EventFlag
  )
{
  USB_XDCI_DEV_CONTEXT            *UsbFuncIoDevPtr;
  UINT32                          EventReg;
  USB_DEV_CORE                    *UsbDeviceCorePtr;
  XDCI_CORE_HANDLE                *XdciCorePtr;

  DEBUG ((USB_FUIO_DEBUG_EVENT_D, "\n FUEV::DeviceEvent entry....\n"));
  UsbFuncIoDevPtr = USBFUIO_CONTEXT_FROM_PROTOCOL (This);
  UsbDeviceCorePtr = UsbFuncIoDevPtr->DrvCore;
  XdciCorePtr = UsbDeviceCorePtr->controller_handle;
  EventReg = (EventIndex->event & DWC_XDCI_EVENT_BUFF_DEV_EVT_MASK);
  EventReg >>= DWC_XDCI_EVENT_BUFF_DEV_EVT_BIT_POS;
  *EventFlag = FALSE;

  /* Assume default event size. Change it in switch case if
   *  different
   */
  *ProcessSize =  DWC_XDCI_DEV_EVENT_DEFAULT_SIZE_IN_BYTES;

  switch (EventReg) {
    case DWC_XDCI_EVENT_BUFF_DEV_DISCONN_EVENT:
      DEBUG ((USB_FUIO_DEBUG_EVENT_D, "USBFU_Device DWC_XDCI_EVENT_BUFF_DEV_DISCONN_EVENT\n"));
      UsbFuncIoDevPtr->DevDisReConnect = TRUE;
      *Message = EfiUsbMsgBusEventDetach;
      break;

    case DWC_XDCI_EVENT_BUFF_DEV_USB_RESET_EVENT:
      DEBUG ((USB_FUIO_DEBUG_EVENT_D, "USBFU_Device DWC_XDCI_EVENT_BUFF_DEV_USB_RESET_EVENT\n"));
      //
      //  In reset_det will prepare setup xfer package
      //
      UsbFuncIoDevPtr->DevReConnect = FALSE;
      UsbFuncIoDevPtr->DevResetFlag = TRUE;
      if(UsbFuncIoDevPtr->DevDisReConnect == TRUE) {
        usb_xdci_core_reinit (XdciCorePtr);
        UsbFuncIoDevPtr->DevDisReConnect = FALSE;
      }
      usb_process_device_reset_det(XdciCorePtr);
      usb_device_set_address (UsbDeviceCorePtr, 0);
      *Message = EfiUsbMsgBusEventReset;
      *EventFlag = TRUE;
      break;

    case DWC_XDCI_EVENT_BUFF_DEV_CONN_DONE_EVENT:
      DEBUG ((USB_FUIO_DEBUG_EVENT_D, "USBFU_Device DWC_XDCI_EVENT_BUFF_DEV_CONN_DONE_EVENT\n"));
      usb_process_device_reset_done(XdciCorePtr);
      usb_device_set_address(UsbDeviceCorePtr, 0);

      *Message = EfiUsbMsgBusEventSpeed;
      if (UsbFuncIoDevPtr->XdciDrvIfHandle->actual_speed == USB_SPEED_SUPER) {
        DEBUG ((USB_FUIO_DEBUG_EVENT_D, "ReportSpeed UsbBusSpeedSuper\n"));
        Payload->ubs = UsbBusSpeedSuper;
      } else {
        DEBUG ((USB_FUIO_DEBUG_EVENT_D, "ReportSpeed UsbBusSpeedHigh\n"));
        Payload->ubs = UsbBusSpeedHigh;
      }

      DEBUG ((USB_FUIO_DEBUG_EVENT_D, "Payload->ubs %02x\n", UsbFuncIoDevPtr->XdciDrvIfHandle->actual_speed ));

      UsbFuncIoDevPtr->DevReConnect = TRUE;
      UsbFuncIoDevPtr->DevResetFlag = FALSE;
      *EventFlag = TRUE;
      break;

    case DWC_XDCI_EVENT_BUFF_DEV_HBRNTN_REQ_EVENT:
      DEBUG ((USB_FUIO_DEBUG_EVENT_D, "USBFU_Device DWC_XDCI_EVENT_BUFF_DEV_HBRNTN_REQ_EVENT\n"));
      *Message = EfiUsbMsgBusEventSuspend;
      *EventFlag = TRUE;
      break;

    case DWC_XDCI_EVENT_BUFF_DEV_WKUP_EVENT:
      DEBUG ((USB_FUIO_DEBUG_EVENT_D, "USBFU_Device DWC_XDCI_EVENT_BUFF_DEV_WKUP_EVENT\n"));
      *Message = EfiUsbMsgBusEventResume;
      break;

    case DWC_XDCI_EVENT_BUFF_DEV_TST_LMP_RX_EVENT:
      *ProcessSize = DWC_XDCI_DEV_EVENT_TST_LMP_SIZE_IN_BYTES;
      *Message = EfiUsbMsgNone;
      DEBUG ((USB_FUIO_DEBUG_EVENT_D, "USBFU_dwc_xdci_process_device_event: UNHANDLED device event: %x\n", EventReg));
      break;

    case DWC_XDCI_EVENT_BUFF_DEV_STATE_CHANGE_EVENT:
      DEBUG ((USB_FUIO_DEBUG_EVENT_D, "USBFU_Device DWC_XDCI_EVENT_BUFF_DEV_STATE_CHANGE_EVENT\n"));
      break;

    case DWC_XDCI_EVENT_BUFF_DEV_SOF_EVENT:
      DEBUG ((USB_FUIO_DEBUG_EVENT_D, "USBFU_Device DWC_XDCI_EVENT_BUFF_DEV_SOF_EVENT\n"));
      break;

    case DWC_XDCI_EVENT_BUFF_DEV_ERRATIC_ERR_EVENT:
      // refer page 457
      usb_process_device_disconnect (XdciCorePtr);
      usb_xdci_core_reinit(XdciCorePtr);
      DEBUG ((USB_FUIO_DEBUG_EVENT_D, "USBFU_Device DWC_XDCI_EVENT_BUFF_DEV_ERRATIC_ERR_EVENT\n"));
      break;

    case DWC_XDCI_EVENT_BUFF_DEV_CMD_CMPLT_EVENT:
      DEBUG ((USB_FUIO_DEBUG_EVENT_D, "USBFU_Device DWC_XDCI_EVENT_BUFF_DEV_CMD_CMPLT_EVENT\n"));
      break;

    case DWC_XDCI_EVENT_BUFF_DEV_BUFF_OVFL_EVENT:
      DEBUG ((USB_FUIO_DEBUG_EVENT_D, "USBFU_Device DWC_XDCI_EVENT_BUFF_DEV_BUFF_OVFL_EVENT\n"));
      break;

    default:
      *EventFlag = FALSE;
      *Message = EfiUsbMsgNone;
      DEBUG ((USB_FUIO_DEBUG_EVENT_I, "USBFU_wc_xdci_process_device_event: UNHANDLED device event: %x\n", EventReg));
      break;
  }

  DEBUG ((USB_FUIO_DEBUG_EVENT_D, "\n FUEV::DeviceEvent entry exit.... \n"));
  return EFI_SUCCESS;
}


EFI_STATUS
Ep0XferDone(
  IN  EFI_USBFN_IO_PROTOCOL       *This,
  IN  UINT32                      EndPointNum,
  OUT EFI_USBFN_MESSAGE           *Message,
  IN OUT UINTN                    *PayloadSize,
  OUT EFI_USBFN_MESSAGE_PAYLOAD   *Payload
  )
{
  USB_DEV_CORE                    *UsbDeviceCorePtr;
  XDCI_CORE_HANDLE                *XdciCorePtr;
  USB_XDCI_DEV_CONTEXT            *UsbFuncIoDevPtr;
  DWC_XDCI_ENDPOINT               *EpHandle;
  DWC_XDCI_TRB                    *Trb;
  UINT32                          TrbCtrl;
  UINT32                          TrbSts;
  UINT32                          BufferLen;
  EFI_STATUS                      DevStatus;
  USB_EP_INFO                     EpInfo;

  UsbFuncIoDevPtr = USBFUIO_CONTEXT_FROM_PROTOCOL (This);
  UsbDeviceCorePtr = UsbFuncIoDevPtr->DrvCore;
  XdciCorePtr = UsbDeviceCorePtr->controller_handle;
  EpHandle = &XdciCorePtr->ep_handles[EndPointNum];
  Trb = XdciCorePtr->trbs + (EndPointNum * DWC_XDCI_TRB_NUM);

  if (Trb->trb_ctrl & DWC_XDCI_TRB_CTRL_HWO_MASK) {
    DEBUG ((USB_FUIO_DEBUG_EVENT_D, "Ep0XferDone. HW owns TRB: %x!!!\n", (UINT32)(UINTN)Trb));
  }

  DevStatus = EFI_SUCCESS;
  BufferLen = 0;

  DEBUG ((USB_FUIO_DEBUG_EVENT_D, "EndPointNum:%d, TRB: Addr 0x%08x!!!\n", EndPointNum, (UINTN)Trb));
  DEBUG ((USB_FUIO_DEBUG_EVENT_D, "Ep0 done Trb->trb_ctrl: %x!!!\n", (UINT32)Trb->trb_ctrl));
  DEBUG ((USB_FUIO_DEBUG_EVENT_D, "Ep0 done Trb->len_xfer_params: %x!!!\n", (UINT32)Trb->len_xfer_params));
  DEBUG ((USB_FUIO_DEBUG_EVENT_D, "Ep0 done Trb->buff_ptr_low: %x!!!\n", (UINT32)Trb->buff_ptr_low));
  DEBUG ((USB_FUIO_DEBUG_EVENT_D, "Ep0 done Trb->buff_ptr_high: %x!!!\n", (UINT32)Trb->buff_ptr_high));

  //
  // Set CheckFlag to FALSE for 'dwc_xdci_ep_rx_data' function
  // check the RX request complete and continue next transfer request
  //
  EpHandle->CheckFlag = FALSE;
  EpHandle->currentXferRscIdx = 0;

  DEBUG ((USB_FUIO_DEBUG_EVENT_I, "Ep0 done D01!!\n"));
  TrbCtrl = (Trb->trb_ctrl & DWC_XDCI_TRB_CTRL_TYPE_MASK) >> DWC_XDCI_TRB_CTRL_TYPE_BIT_POS;

  DEBUG ((USB_FUIO_DEBUG_EVENT_I, "Ep0 done D02!!\n"));
  TrbSts = (Trb->len_xfer_params & DWC_XDCI_TRB_STATUS_MASK) >> DWC_XDCI_TRB_STATUS_BIT_POS;

  DEBUG ((USB_FUIO_DEBUG_EVENT_I, "Ep0 done D03!!\n" ));
  BufferLen = Trb->len_xfer_params & DWC_XDCI_TRB_BUFF_SIZE_MASK;

  DEBUG ((USB_FUIO_DEBUG_EVENT_I, "Ep0 done D04 TrbCtrl :: %x!!\n", TrbCtrl));
  switch (TrbCtrl) {
    case DWC_XDCI_TRB_CTRL_TYPE_SETUP:
      DEBUG ((USB_FUIO_DEBUG_EVENT_D, "Ep0 done DWC_XDCI_TRB_CTRL_TYPE_SETUP!!\n"));
      //
      // This is delay for other host USB controller(none Intel), identify device get fail issue.
      //
      gBS->Stall(130);
      BufferLen = 8;

      if (UsbFuncIoDevPtr->EndPointXferRec[EndPointNum].Ep0RxData == TRUE) {

        UsbFuncIoDevPtr->EndPointXferRec[EndPointNum].Ep0RxData = FALSE;

        *Message = EfiUsbMsgEndpointStatusChangedRx;
        Payload->utr.EndpointIndex = (UINT8)(EndPointNum >> 1);
        Payload->utr.Direction = (UINT8)(EndPointNum & 0x01);
        Payload->utr.TransferStatus = UsbTransferStatusComplete;
        Payload->utr.BytesTransferred  = UsbFuncIoDevPtr->EndPointXferRec[EndPointNum].XferLength;

        DEBUG ((USB_FUIO_DEBUG_EVENT_D, "Payload->utr.BytesTransferred::0x%08x!!\n",\
                                                       (UINTN)Payload->utr.BytesTransferred));
        DEBUG ((USB_FUIO_DEBUG_EVENT_D, "UsbFuncIoDevPtr->EndPointXferRec[EndPointNum].XferLength::0x%08x!!\n", \
                                                 (UINTN)UsbFuncIoDevPtr->EndPointXferRec[EndPointNum].XferLength));

        CopyMem ((UINT8*)UsbFuncIoDevPtr->EndPointXferRec[EndPointNum].XferAddress, \
                                                  XdciCorePtr->aligned_setup_buffer, \
                                                  UsbFuncIoDevPtr->EndPointXferRec[EndPointNum].XferLength);
        break;
      }

      DEBUG ((USB_FUIO_DEBUG_EVENT_D, "DWC_XDCI_TRB_CTRL_TYPE_SETUP!!\n"));
      DEBUG ((USB_FUIO_DEBUG_EVENT_D, "aligned_setup_buffer::0x%08x!!\n", XdciCorePtr->aligned_setup_buffer));
      DEBUG ((USB_FUIO_DEBUG_EVENT_D, "Payload::0x%08x!!\n", (UINTN)Payload));
      DEBUG ((USB_FUIO_DEBUG_EVENT_D, "BufferLen::0x%08x!!\n", (UINTN)BufferLen));
      *Message = EfiUsbMsgSetupPacket;
      CopyMem (Payload, XdciCorePtr->aligned_setup_buffer, BufferLen);

      DEBUG ((USB_FUIO_DEBUG_EVENT_I, "Ep0 done D06!!\n"));
      if (!(XdciCorePtr->aligned_setup_buffer[0] & USB_SETUP_DATA_PHASE_DIRECTION_MASK)) {
        /* Keep a buffer ready for setup phase */
        // dwc_xdci_core_start_ep0_setup_xfer(XdciCorePtr);
        if ((XdciCorePtr->aligned_setup_buffer[0]  == 0x00) ) {
          if ((XdciCorePtr->aligned_setup_buffer[1]  == USB_DEV_SET_ADDRESS)) {
            // set address
            UsbSetAddress (
              This,
              (UINT32)(XdciCorePtr->aligned_setup_buffer[3] << 8 | XdciCorePtr->aligned_setup_buffer[2])
              );

            *Message = EfiUsbMsgNone;
          } else if ((XdciCorePtr->aligned_setup_buffer[1]  == USB_DEV_SET_CONFIGURATION)) {
            DEBUG ((USB_FUIO_DEBUG_EVENT_I, "\n set configure !!!"));
            UsbSetconfigure (
              This,
              (UINT32)(XdciCorePtr->aligned_setup_buffer[3] << 8 | XdciCorePtr->aligned_setup_buffer[2])
              );
          } else if ((XdciCorePtr->aligned_setup_buffer[1]  == 0x00))  {

            DEBUG ((USB_FUIO_DEBUG_EVENT_D, "Got NULL Package resend RX_SETUP!!\n"));
            usb_device_ep0_rx_setup (UsbDeviceCorePtr, XdciCorePtr->aligned_setup_buffer);
          }
        }
      }

      DEBUG ((USB_FUIO_DEBUG_EVENT_I, "Ep0 done D07!!\n"));
      break;

    case DWC_XDCI_TRB_CTRL_TYPE_DATA:
      DEBUG ((DEBUG_INFO, "Ep0 done DWC_XDCI_TRB_CTRL_TYPE_DATA!!\n"));
      /* Notify upper layer of control transfer completion
       * if a callback function was registerd
       */

      if ((EndPointNum & 0x01) == 0) {
        *Message = EfiUsbMsgEndpointStatusChangedRx;
      } else {
        *Message = EfiUsbMsgEndpointStatusChangedTx;
      }
      //Payload->utr.BytesTransferred = (Trb->buff_ptr_high - Trb->buff_ptr_low);
      Payload->utr.EndpointIndex = (UINT8)(EndPointNum >> 1);
      Payload->utr.Direction = (UINT8)(EndPointNum & 0x01);
      Payload->utr.Buffer = (VOID*)(UINTN)(Trb->buff_ptr_low);

      DEBUG ((DEBUG_INFO, "Ep0 EndPointNum: %x!!!\n", (UINT32)EndPointNum));
      DEBUG ((DEBUG_INFO, "Ep0 done XferLength: %x!!!\n", (UINT32)UsbFuncIoDevPtr->EndPointXferRec[EndPointNum].XferLength));
      Payload->utr.Buffer = (VOID*)UsbFuncIoDevPtr->EndPointXferRec[EndPointNum].XferAddress;
      Payload->utr.BytesTransferred = UsbFuncIoDevPtr->EndPointXferRec[EndPointNum].XferLength;

      if (TrbSts == 0) {
        if ((Trb->len_xfer_params & DWC_XDCI_TRB_BUFF_SIZE_MASK) == 0) {
          Payload->utr.TransferStatus = UsbTransferStatusComplete;
        } else {
          Payload->utr.TransferStatus = UsbTransferStatusActive;
        }
      } else if (TrbSts != 0) {
        Trb->trb_ctrl |= DWC_XDCI_TRB_CTRL_HWO_MASK;
        *Message = EfiUsbMsgNone;
        Payload->utr.TransferStatus = UsbTransferStatusAborted;
        DEBUG ((DEBUG_INFO, "Flush FIFO!!!\n" ));
        EpInfo.ep_num = 0;
        EpInfo.ep_dir =UsbEpDirIn;
        usb_xdci_core_flush_ep_fifo(XdciCorePtr, &EpInfo);
        EpInfo.ep_num = 0;
        EpInfo.ep_dir =UsbEpDirOut;
        usb_xdci_core_flush_ep_fifo(XdciCorePtr, &EpInfo);
        DevStatus = usb_device_ep0_rx_setup (UsbDeviceCorePtr, XdciCorePtr->aligned_setup_buffer);
      }

      break;

    case DWC_XDCI_TRB_CTRL_TYPE_STATUS2:
    case DWC_XDCI_TRB_CTRL_TYPE_STATUS3:
      Payload->utr.Buffer = (VOID*) UsbFuncIoDevPtr->EndPointXferRec[EndPointNum].XferAddress;
      Payload->utr.BytesTransferred = 0;
      Payload->utr.EndpointIndex = (UINT8)(EndPointNum >> 1);
      if ((EndPointNum & 0x01) == 0) {
        *Message = EfiUsbMsgEndpointStatusChangedRx;
      } else {
        *Message = EfiUsbMsgEndpointStatusChangedTx;
      }

      if (TrbSts == 0) {
        if ((Trb->len_xfer_params & DWC_XDCI_TRB_BUFF_SIZE_MASK) == 0) {
          Payload->utr.TransferStatus = UsbTransferStatusComplete;
        } else {
          Payload->utr.TransferStatus = UsbTransferStatusActive;
        }
      } else if (TrbSts != 0) {
        Payload->utr.TransferStatus = UsbTransferStatusAborted;
      }

      DevStatus = usb_device_ep0_rx_setup (UsbDeviceCorePtr, XdciCorePtr->aligned_setup_buffer);

      if (DevStatus) {
        DEBUG ((DEBUG_INFO, "dwc_xdci_process_ep0_xfer_phase_done: FAILED to queue SETUP\n"));
      }
      DEBUG ((DEBUG_INFO, "Status phase done. Queue next SETUP packet==>\n"));
      break;

    default:
      *Message = EfiUsbMsgNone;
      DEBUG ((DEBUG_INFO, "dwc_xdci_process_ep0_xfer_phase_done: UNHANDLED STATE in TRB\n"));
      break;
  }
  return EFI_SUCCESS;
}


EFI_STATUS
NoneEp0XferDone(
  IN  EFI_USBFN_IO_PROTOCOL       *This,
  IN  UINT32                      EndPointNum,
  OUT EFI_USBFN_MESSAGE           *Message,
  IN OUT UINTN                    *PayloadSize,
  OUT EFI_USBFN_MESSAGE_PAYLOAD   *Payload
  )
{
  USB_DEV_CORE                    *UsbDeviceCorePtr;
  XDCI_CORE_HANDLE                *XdciCorePtr;
  USB_XDCI_DEV_CONTEXT            *UsbFuncIoDevPtr;
  DWC_XDCI_ENDPOINT               *EpHandle;
  DWC_XDCI_TRB                    *Trb;
  UINT32                          TrbCtrl;
  UINT32                          TrbSts;
  UINTN                           TmpBufferSize;
  UINT8                           EndpointIndex;

  UsbFuncIoDevPtr = USBFUIO_CONTEXT_FROM_PROTOCOL (This);
  UsbDeviceCorePtr = UsbFuncIoDevPtr->DrvCore;
  XdciCorePtr = UsbDeviceCorePtr->controller_handle;
  EpHandle = &XdciCorePtr->ep_handles[EndPointNum];
  Trb = XdciCorePtr->trbs + (EndPointNum * DWC_XDCI_TRB_NUM);

  if (Trb->trb_ctrl & DWC_XDCI_TRB_CTRL_HWO_MASK) {
    DEBUG ((USB_FUIO_DEBUG_EVENT_D, "NoneEp0XferDone. HW owns TRB: %x!!!, EndPointNum: %x\n", (UINT32)(UINTN)Trb, EndPointNum));
  }

  DEBUG ((USB_FUIO_DEBUG_EVENT_D, " TRB: Addr 0x%08x!!!\n", (UINTN)Trb));
  DEBUG ((USB_FUIO_DEBUG_EVENT_D, " Xfer done Trb->buff_ptr_low: %x!!!\n", (UINT32)Trb->buff_ptr_low));
  DEBUG ((USB_FUIO_DEBUG_EVENT_D, " Xfer done Trb->buff_ptr_high: %x!!!\n", (UINT32)Trb->buff_ptr_high));
  DEBUG ((USB_FUIO_DEBUG_EVENT_D, " Xfer done Trb->len_xfer_params: %x!!!\n", (UINT32)Trb->len_xfer_params));
  DEBUG ((USB_FUIO_DEBUG_EVENT_D, " Xfer done Trb->trb_ctrl: %x!!!\n", (UINT32)Trb->trb_ctrl));

  //
  // Set CheckFlag to FALSE for 'dwc_xdci_ep_rx_data' function
  // check the RX request complete and continue next transfer request
  //
  EpHandle->CheckFlag = FALSE;
  EpHandle->currentXferRscIdx = 0;
  *Message = EfiUsbMsgNone;

  TrbCtrl = (Trb->trb_ctrl & DWC_XDCI_TRB_CTRL_TYPE_MASK) >> DWC_XDCI_TRB_CTRL_TYPE_BIT_POS;
  TrbSts = (Trb->len_xfer_params & DWC_XDCI_TRB_STATUS_MASK) >> DWC_XDCI_TRB_STATUS_BIT_POS;

  Payload->utr.EndpointIndex = UsbFuncIoDevPtr->EndPointXferRec[EndPointNum].LogEpNum;
  Payload->utr.Direction = UsbFuncIoDevPtr->EndPointXferRec[EndPointNum].Direction;
  Payload->utr.Buffer = (VOID*)(UINTN)(Trb->buff_ptr_low);
  Payload->utr.BytesTransferred = UsbFuncIoDevPtr->EndPointXferRec[EndPointNum].ActualXferLength;
  UsbFuncIoDevPtr->EndPointXferRec[EndPointNum].Complete = TRUE;

  DEBUG ((USB_FUIO_DEBUG_EVENT_D, "EndPointAddress = 0x%08x\n", Payload->utr.EndpointIndex));
  if (Payload->utr.Direction == EfiUsbEndpointDirectionDeviceTx) {
    DEBUG ((USB_FUIO_DEBUG_EVENT_D, " Direction::EfiUsbEndpointDirectionDeviceTx\n"));
    *Message = EfiUsbMsgEndpointStatusChangedTx;
  } else {
    DEBUG ((USB_FUIO_DEBUG_EVENT_D, " Direction::EfiUsbEndpointDirectionDeviceRx\n"));
    *Message = EfiUsbMsgEndpointStatusChangedRx;
  }

  if (TrbSts == 0) {
    if ((Trb->len_xfer_params & DWC_XDCI_TRB_BUFF_SIZE_MASK) == 0) {
      Payload->utr.TransferStatus = UsbTransferStatusComplete;
      DEBUG ((USB_FUIO_DEBUG_EVENT_D, "XferStatus::UsbTransferStatusComplete\n"));
    } else {
      Payload->utr.TransferStatus = UsbTransferStatusComplete;
      Payload->utr.BytesTransferred -= (Trb->len_xfer_params & DWC_XDCI_TRB_BUFF_SIZE_MASK);
      DEBUG ((USB_FUIO_DEBUG_EVENT_D, "XferStatus::UsbTransferStatusComplete\n"));
      DEBUG ((USB_FUIO_DEBUG_EVENT_D, "XferStatus::Length %d \n", Payload->utr.BytesTransferred ));
    }
  } else if (TrbSts != 0) {
    Payload->utr.TransferStatus = UsbTransferStatusAborted;
    DEBUG ((USB_FUIO_DEBUG_EVENT_D, "XferStatus::UsbTransferStatusAborted\n"));
  }

  if (UsbFuncIoDevPtr->EndPointXferRec[EndPointNum].ZlpActive == TRUE) {
    DEBUG ((USB_FUIO_DEBUG_EVENT_D, "ZLP completed. Sending Payload Response data from original transfer\n"));
    CopyMem(&Payload->utr, &UsbFuncIoDevPtr->EndPointXferRec[EndPointNum].ZlpPendingTransferResult, sizeof(EFI_USBFN_TRANSFER_RESULT));
    UsbFuncIoDevPtr->EndPointXferRec[EndPointNum].ZlpActive = FALSE;
    *Message = EfiUsbMsgEndpointStatusChangedTx;
  } else if ((UsbFuncIoDevPtr->EndPointXferRec[EndPointNum].ZlpFlag == TRUE) && (UsbFuncIoDevPtr->EndPointXferRec[EndPointNum].Complete == TRUE)) {
    if ((EndPointNum & 0x01) != 0) {
      DEBUG ((USB_FUIO_DEBUG_EVENT_D, "ZLP requested. Caching original payload and queuing ZLP transfer.\n"));
      CopyMem(&UsbFuncIoDevPtr->EndPointXferRec[EndPointNum].ZlpPendingTransferResult, &Payload->utr, sizeof(EFI_USBFN_TRANSFER_RESULT));
      UsbFuncIoDevPtr->EndPointXferRec[EndPointNum].ZlpActive = TRUE;
      TmpBufferSize = 0;
      if (UsbFuncIoDevPtr->XdciDrvIfHandle->actual_speed == USB_SPEED_SUPER) {
        EndpointIndex = UsbFuncIoDevPtr->SSIndexPtrInEp.EndpointDesc->EndpointAddress;
      } else {
        EndpointIndex = UsbFuncIoDevPtr->IndexPtrInEp.EndpointDesc->EndpointAddress;
      }
      Transfer(This,
                EndpointIndex,
                EfiUsbEndpointDirectionDeviceTx,
                &TmpBufferSize,
                NULL
              );
      *Message = EfiUsbMsgNone;
    } else {
      DEBUG ((USB_FUIO_DEBUG_ERROR, "ZLP requested on bad Endpoint!\n"));
      ASSERT(FALSE); //Just proceed without scheduling the ZLP transfer in this case.
    }
    UsbFuncIoDevPtr->EndPointXferRec[EndPointNum].ZlpFlag = FALSE;
  }
  return EFI_SUCCESS;
}

EFI_STATUS
Ep0XferNotReady(
  IN  EFI_USBFN_IO_PROTOCOL       *This,
  IN  UINT32                      EndPointNum,
  OUT EFI_USBFN_MESSAGE           *Message,
  IN OUT UINTN                    *PayloadSize,
  OUT EFI_USBFN_MESSAGE_PAYLOAD   *Payload,
  IN  UINT32                      EpStatus
  )
{
  USB_DEV_CORE                    *UsbDeviceCorePtr;
  XDCI_CORE_HANDLE                *XdciCorePtr;
  USB_XDCI_DEV_CONTEXT            *UsbFuncIoDevPtr;

  UsbFuncIoDevPtr = USBFUIO_CONTEXT_FROM_PROTOCOL(This);
  UsbDeviceCorePtr = UsbFuncIoDevPtr->DrvCore;
  XdciCorePtr = UsbDeviceCorePtr->controller_handle;

  if ((EpStatus & DWC_XDCI_EVENT_BUFF_EP_CTRL_STATUS_REQ_MASK) != 0) {
    //
    // Check need to do ??
    //
  }

  *Message = EfiUsbMsgNone;

  return EFI_SUCCESS;
}


EFI_STATUS
EpEventCheck(
  IN  EFI_USBFN_IO_PROTOCOL       *This,
  IN  USBD_EVENT_BUF              *EventIndex,
  OUT UINT32                      *ProcessSize,
  OUT EFI_USBFN_MESSAGE           *Message,
  IN OUT UINTN                    *PayloadSize,
  OUT EFI_USBFN_MESSAGE_PAYLOAD   *Payload,
  OUT BOOLEAN                     *EventFlag
  )
{
  USB_DEV_CORE                    *UsbDeviceCorePtr;
  XDCI_CORE_HANDLE                *XdciCorePtr;
  USB_XDCI_DEV_CONTEXT            *UsbFuncIoDevPtr;
  UINT32                          EventReg;
  UINT32                          EpEvent;
  UINT32                          EndPointNumber;
  UINT32                          EventStatus;

   DEBUG ((USB_FUIO_DEBUG_EVENT_I, "FUEV::EndPoint Event....\n"));
  UsbFuncIoDevPtr = USBFUIO_CONTEXT_FROM_PROTOCOL(This);

  UsbDeviceCorePtr = UsbFuncIoDevPtr->DrvCore;
  XdciCorePtr = UsbDeviceCorePtr->controller_handle;
  EventReg = EventIndex->event;
  *ProcessSize = DWC_XDCI_DEV_EVENT_DEFAULT_SIZE_IN_BYTES;
  *EventFlag = TRUE;

  /* Get EP num */
  EndPointNumber = (EventReg & DWC_XDCI_EVENT_BUFF_EP_NUM_MASK) >> DWC_XDCI_EVENT_BUFF_EP_NUM_BIT_POS;

  EventStatus = EventReg & DWC_XDCI_EVENT_BUFF_EP_EVENT_STATUS_MASK;

  /* Interpret event and handle transfer completion here */
  EpEvent = (EventReg & DWC_XDCI_EVENT_BUFF_EP_EVENT_MASK) >> DWC_XDCI_EVENT_BUFF_EP_EVENT_BIT_POS;

  DEBUG ((USB_FUIO_DEBUG_EVENT_I, "USBFU_EP EventReg 0x%08x\n", EventReg));

  switch (EpEvent) {
    case DWC_XDCI_EVENT_BUFF_EP_XFER_CMPLT:
      DEBUG ((USB_FUIO_DEBUG_EVENT_D, "USBFU_EP DWC_XDCI_EVENT_BUFF_EP_XFER_CMPLT\n"));
      if (EndPointNumber > 1) {
        DEBUG ((USB_FUIO_DEBUG_EVENT_D, "USBFU_EP None_Control transfer\n"));
        NoneEp0XferDone (This, EndPointNumber, Message, PayloadSize, Payload);
      } else {
        //
        // Control transfer
        //
        DEBUG ((USB_FUIO_DEBUG_EVENT_D, "USBFU_EP Control transfer\n"));
        Ep0XferDone (This, EndPointNumber, Message, PayloadSize, Payload);
      }
      break;

    case DWC_XDCI_EVENT_BUFF_EP_XFER_NOT_READY:
      DEBUG ((USB_FUIO_DEBUG_EVENT_D, "DWC_XDCI_EVENT_BUFF_EP_XFER_NOT_READY\n"));
      *Message = EfiUsbMsgNone;
      break;

    case DWC_XDCI_EVENT_BUFF_EP_XFER_IN_PROGRESS:
      DEBUG ((USB_FUIO_DEBUG_EVENT_D, "DWC_XDCI_EVENT_BUFF_EP_XFER_IN_PROGRESS\n"));
      break;

    default:
      DEBUG ((USB_FUIO_DEBUG_EVENT_I, "USBFU_dwc_xdci_process_ep_event: UNKNOWN EP event\n"));
      break;
  }

  DEBUG ((USB_FUIO_DEBUG_EVENT_D, "FUEV::EndPoint Event....exit\n"));
  return EFI_SUCCESS;
}


EFI_STATUS
ProcessIntLineEvents(
  IN EFI_USBFN_IO_PROTOCOL        *This,
  IN UINT32                       EventCount,
  IN UINT32                       *ProcessEvent,
  OUT EFI_USBFN_MESSAGE           *Message,
  IN OUT UINTN                    *PayloadSize,
  OUT EFI_USBFN_MESSAGE_PAYLOAD   *Payload,
  OUT BOOLEAN                     *EventFlag
  )
{
  USB_DEV_CORE                    *UsbDeviceCorePtr;
  XDCI_CORE_HANDLE                *XdciCorePtr;
  USB_XDCI_DEV_CONTEXT            *UsbFuncIoDevPtr;
  UINT32                          CurrentEventAddr;
  UINT32                          ProcessEventSize;
  BOOLEAN                         EventReport;
  BOOLEAN                         EpEventReport;

  UsbFuncIoDevPtr = USBFUIO_CONTEXT_FROM_PROTOCOL (This);
  UsbDeviceCorePtr = UsbFuncIoDevPtr->DrvCore;
  XdciCorePtr = UsbDeviceCorePtr->controller_handle;
  CurrentEventAddr = (UINT32)(UINTN)(XdciCorePtr->current_event_buffer);
  EventReport = FALSE;
  EpEventReport = FALSE;
  ProcessEventSize = 0;
   DEBUG ((USB_FUIO_DEBUG_EVENT_I, "FUEV:: ProcessIntLineEvents Entry\n"));

   DEBUG ((USB_FUIO_DEBUG_EVENT_I, "FUEV:: XdciCorePtr->current_event_buffer 0x%08x\n", XdciCorePtr->current_event_buffer));
   DEBUG ((USB_FUIO_DEBUG_EVENT_I, "FUEV::EventCount0x%08x\n", EventCount));
   DEBUG ((USB_FUIO_DEBUG_EVENT_I, "FUEV::CurrentEventAddr 0x%08x\n", CurrentEventAddr));

  while ((EventCount != 0) && (EventReport == FALSE)) {
     DEBUG ((USB_FUIO_DEBUG_EVENT_D, "FUEV::event0x%08x\n", XdciCorePtr->current_event_buffer->event));
     if ((XdciCorePtr->current_event_buffer->event & DWC_XDCI_EVENT_DEV_MASK) != 0) {
       //
       // Device event
       //
       DeviceEventCheck (
         This,
         (USBD_EVENT_BUF*)(UINTN)CurrentEventAddr,
         &ProcessEventSize,
         Message,
         PayloadSize,
         Payload,
         &EventReport
         );
       if (EventReport == TRUE) {
         *EventFlag = TRUE;
       }

     } else {
       //
       // EndPoint Event
       //
       EpEventCheck (
         This,
         (USBD_EVENT_BUF*)(UINTN)CurrentEventAddr,
         &ProcessEventSize,
         Message,
         PayloadSize,
         Payload,
         &EpEventReport
         );
     }

     if ((*Message != EfiUsbMsgNone) || (EpEventReport == TRUE)) {
       EventReport = TRUE;
       *EventFlag = TRUE;
     }

     DEBUG ((USB_FUIO_DEBUG_EVENT_D, "FUEV:: CurrentEventAddr 0x%08x :: ProcessEventSize 0x%08x\n", (UINTN)CurrentEventAddr,ProcessEventSize));

     EventCount -= ProcessEventSize;
     *ProcessEvent += ProcessEventSize;
     if ((CurrentEventAddr + ProcessEventSize) >= \
         ((UINT32)(UINTN)(XdciCorePtr->aligned_event_buffers) +
          (sizeof(DWC_XDCI_EVENT_BUFFER) * DWC_XDCI_MAX_EVENTS_PER_BUFFER))) {
       CurrentEventAddr = (UINT32)(UINTN)(XdciCorePtr->aligned_event_buffers);
     //DEBUG ((DEBUG_INFO, "FUEV::dwc_xdci_process_interrupt_line_events: Event buffer bound reached\n"));
    } else {
      CurrentEventAddr += ProcessEventSize;
    }
    DEBUG ((USB_FUIO_DEBUG_EVENT_D, "FUEV:: CurrentEventAddr Update 0x%08x :: ProcessEventSize 0x%08x\n", CurrentEventAddr,ProcessEventSize));

    XdciCorePtr->current_event_buffer = (DWC_XDCI_EVENT_BUFFER*)(UINTN)CurrentEventAddr;
  } // While end

  DEBUG ((USB_FUIO_DEBUG_EVENT_I, "FUEV:: ProcessIntLineEvents Exit\n\n"));
  return EFI_SUCCESS;
}


/**
  ISR inokes Event Handler.  Look at which interrupt has happened and see
  if there are event handler registerd and if so fire them 1 by one.

  @param[in]  This              A pointer to the EFI_USBFN_IO_PROTOCOL instance.
  @param[in]  Message           Indicates the event that initiated this
                                notification.
  @param[in]  PayloadSize       On input, the size of the memory pointed by Payload.
                                On output, the amount of data returned in Payload.
  @param[in]  Payload           A pointer to EFI_USBFN_MESSAGE_PAYLOAD instance to
                                return additional payload for current message.




  @retval EFI_SUCCESS           The function returned successfully.
  @retval EFI_INVALID_PARAMETER A parameter is invalid.
  @retval EFI_DEVICE_ERROR      The physical device reported an error.
  @retval EFI_NOT_READY         The physical device is busy or not ready to
                                process this request.
  @retval EFI_BUFFER_TOO_SMALL  Supplied buffer not large enough to hold
                                the message payload.

**/
EFI_STATUS
EFIAPI
EventHandler(
  IN EFI_USBFN_IO_PROTOCOL        *This,
  OUT EFI_USBFN_MESSAGE           *Message,
  IN OUT UINTN                    *PayloadSize,
  OUT EFI_USBFN_MESSAGE_PAYLOAD   *Payload
  )
{
  UINT32                          EventCount;
  UINT32                          PeventCount;
  USB_XDCI_DEV_CONTEXT            *UsbFuncIoDevPtr;
  UINT32                          MaxIntNum;
  UINT32                          IntIndex;
  USB_DEV_CORE                    *UsbDeviceCorePtr;
  XDCI_CORE_HANDLE                *XdciCorePtr;
  BOOLEAN                         EventFlag;
  EFI_TPL                         OriginalTpl;


  DEBUG ((USB_FUIO_DEBUG_EVENT_I, "USBFU_ EventHandler Entry\n"));
  UsbFuncIoDevPtr = USBFUIO_CONTEXT_FROM_PROTOCOL (This);

  if (UsbFuncIoDevPtr->StartUpController == FALSE) {
    UsbFnInitDevice (This);
  }
  OriginalTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
  *Message = EfiUsbMsgNone;
  MaxIntNum = (usb_reg_read ((UINT32)UsbFuncIoDevPtr->XdciMmioBarAddr, DWC_XDCI_GHWPARAMS1_REG) &
                 DWC_XDCI_GHWPARAMS1_NUM_INT_MASK) >>
                 DWC_XDCI_GHWPARAMS1_NUM_INT_BIT_POS;

  UsbDeviceCorePtr = UsbFuncIoDevPtr->DrvCore;
  XdciCorePtr = UsbDeviceCorePtr->controller_handle;
  EventFlag = TRUE;

  DEBUG ((USB_FUIO_DEBUG_EVENT_I, "XdciCorePtr->max_dev_int_lines 0x%08x\n", XdciCorePtr->max_dev_int_lines));
  EventCount = usb_reg_read ((UINT32)UsbFuncIoDevPtr->XdciMmioBarAddr, DWC_XDCI_EVNTCOUNT_REG(0));
  //DEBUG ((USB_FUIO_DEBUG_EVENT_D, "\n ==>> EventCount = 0x%08x \n", EventCount));

  for (IntIndex = 0; IntIndex < XdciCorePtr->max_dev_int_lines ; IntIndex++) {
    /* Get the number of events HW has written for this
     *  interrupt line
     */
    EventCount = usb_reg_read ((UINT32)UsbFuncIoDevPtr->XdciMmioBarAddr, DWC_XDCI_EVNTCOUNT_REG(IntIndex));
    EventCount &= DWC_XDCI_EVNTCOUNT_MASK;
    PeventCount = 0;

    /* Process interrupt line buffer only if count is non-zero */
    if (EventCount) {
      /* Process events in this buffer */
      ProcessIntLineEvents (
        This,
        EventCount,
        &PeventCount,
        Message,
        PayloadSize,
        Payload,
        &EventFlag
        );

      /* Write back the processed number of events so HW decrements it from current
       * event count
       */
      usb_reg_write ((UINT32)UsbFuncIoDevPtr->XdciMmioBarAddr, DWC_XDCI_EVNTCOUNT_REG(IntIndex), PeventCount);

      //
      // for debug
      //
      if (*Message != EfiUsbMsgNone) {
        break;
      }

      if (EventFlag == TRUE) {
        break;
      }
    }
  }

  gBS->RestoreTPL (OriginalTpl);

//EVENT_EXIT:
  DEBUG ((USB_FUIO_DEBUG_EVENT_I, "USBFU_ EventHandler Exit\n"));
  return EFI_SUCCESS;
}



/**
  Copies relevant endpoint data from standard USB endpoint descriptors
  to the usb_ep_info structure used by the XDCI

  @param pEpDest   destination structure
  @param pEpSrc    source structure

  @return VOID

**/
VOID
UsbFnSetEpInfo (
  IN USB_EP_INFO                 *EpDest,
  IN USB_DEVICE_ENDPOINT_INFO    *EpSrc
  )
{
  EFI_USB_ENDPOINT_DESCRIPTOR              *EpDesc = NULL;
  EFI_USB_ENDPOINT_COMPANION_DESCRIPTOR    *EpCompDesc = NULL;

  /* start by clearing all data in the destination */
  SetMem (EpDest, sizeof(USB_EP_INFO), 0);
  EpDesc = EpSrc->EndpointDesc;
  EpCompDesc = EpSrc->EndpointCompDesc;

  if (EpDesc != NULL) {
    EpDest->ep_num = EpDesc->EndpointAddress & 0x0F; /* Bits 0-3 are ep num */
    EpDest->ep_dir = ((EpDesc->EndpointAddress & USB_ENDPOINT_DIR_IN) > 0) ? UsbEpDirIn : UsbEpDirOut;
    DEBUG ((DEBUG_INFO, "EpDest->ep_num 0x%02x\n", EpDest->ep_num));
    DEBUG ((DEBUG_INFO, "EpDest->ep_dir 0x%02x\n", EpDest->ep_dir));
    EpDest->ep_type = EpDesc->Attributes & USB_ENDPOINT_TYPE_MASK;
    EpDest->max_pkt_size = EpDesc->MaxPacketSize;
    EpDest->interval = EpDesc->Interval;
  }
  if (EpCompDesc != NULL) {
    EpDest->max_streams = EpCompDesc->Attributes & USB_EP_BULK_BM_ATTR_MASK;
    EpDest->burst_size = EpCompDesc->MaxBurst;
    EpDest->mult = EpCompDesc->BytesPerInterval;
  }

  return;
}


EFI_STATUS
SetFnIoReqInfo(
  IN     EFI_USBFN_IO_PROTOCOL         *This,
  IN     UINT8                         EndpointIndex,
  IN     EFI_USBFN_ENDPOINT_DIRECTION  Direction,
  IN OUT UINTN                         *BufferSize,
  IN OUT VOID                          *Buffer,
  IN OUT USB_XFER_REQUEST              *XfIoreq
  )
{
  USB_XDCI_DEV_CONTEXT     *UsbFuncIoDevPtr;
  EFI_STATUS               Status;
  UINTN                    ReqPacket;

  UsbFuncIoDevPtr = USBFUIO_CONTEXT_FROM_PROTOCOL (This);
  Status = EFI_SUCCESS;
  ReqPacket = 0;

  switch (EndpointIndex) {
    case 0: // Control endpoint
      XfIoreq->ep_info.ep_num = 0;
      XfIoreq->ep_info.ep_dir = Direction? UsbEpDirIn : UsbEpDirOut;
      XfIoreq->xfer_len = (UINT32)(*BufferSize);
      break;


    default:
      if (Direction == EfiUsbEndpointDirectionDeviceTx) {
        if (UsbFuncIoDevPtr->XdciDrvIfHandle->actual_speed != USB_SPEED_SUPER) {
          UsbFnSetEpInfo(&XfIoreq->ep_info, &UsbFuncIoDevPtr->IndexPtrInEp);
        }
        else {
          UsbFnSetEpInfo(&XfIoreq->ep_info, &UsbFuncIoDevPtr->SSIndexPtrInEp);
        }
        XfIoreq->xfer_len = (UINT32)(*BufferSize);
      } else {
        if (UsbFuncIoDevPtr->XdciDrvIfHandle->actual_speed != USB_SPEED_SUPER) {
          UsbFnSetEpInfo(&XfIoreq->ep_info, &UsbFuncIoDevPtr->IndexPtrOutEp);
        }
        else {
          UsbFnSetEpInfo(&XfIoreq->ep_info, &UsbFuncIoDevPtr->SSIndexPtrOutEp);
        }
        //
        // reference from "UsbDeviceMode.c", function UsbdEpRxData
        //

        //
        // Transfer length should be multiple of USB packet size.
        //
        ReqPacket = *BufferSize/ XfIoreq->ep_info.max_pkt_size;
        ReqPacket = (((*BufferSize) % XfIoreq->ep_info.max_pkt_size) == 0)? ReqPacket : ReqPacket + 1;

        DEBUG ((USB_FUIO_DEBUG_LOAD, "\n FU:XfIoreq->ep_info.max_pkt_size 0x%08x\n", XfIoreq->ep_info.max_pkt_size));
        DEBUG ((USB_FUIO_DEBUG_LOAD, "\n FU:ReqPacket 0x%08x\n", ReqPacket));

        XfIoreq->xfer_len = (UINT32)ReqPacket * XfIoreq->ep_info.max_pkt_size;
        DEBUG ((USB_FUIO_DEBUG_LOAD, "\n FU:XfIoreq->xfer_len 0x%08x\n", XfIoreq->xfer_len));

      }
      break;
  }

  if (EFI_ERROR(Status)) {
    return EFI_UNSUPPORTED;
  }

  XfIoreq->xfer_buffer = Buffer;
  XfIoreq->xfer_done = NULL;

  return EFI_SUCCESS;
}


/**
  Primary function to handle transfer in either direction based on specified
  direction and on the specified endpoint.

  @param[in]  This              A pointer to the EFI_USBFN_IO_PROTOCOL instance.
  @param[in]  EndpointIndex     Indicates the endpoint on which TX or RX transfer
                                needs to take place.
  @param[in]  Direction         Direction of the endpoint.
  @param[in]  BufferSize        If Direction is EfiUsbEndpointDirectionDeviceRx:
                                On input, the size of the Buffer in bytes.
                                On output, the amount of data returned in Buffer in bytes.
                                If Direction is EfiUsbEndpointDirectionDeviceTx:
                                On input, the size of the Buffer in bytes.
                                On output, the amount of data actually transmitted in bytes.
  @param[in]  Buffer            If Direction is EfiUsbEndpointDirectionDeviceRx:
                                The Buffer to return the received data.
                                If Direction is EfiUsbEndpointDirectionDeviceTx:
                                The Buffer that contains the data to be transmitted.

  @retval EFI_SUCCESS           The function returned successfully.
  @retval EFI_INVALID_PARAMETER A parameter is invalid.
  @retval EFI_DEVICE_ERROR      The physical device reported an error.
  @retval EFI_NOT_READY         The physical device is busy or not ready to
                                process this request.

**/
EFI_STATUS
EFIAPI
Transfer (
  IN EFI_USBFN_IO_PROTOCOL         *This,
  IN UINT8                         EndpointIndex,
  IN EFI_USBFN_ENDPOINT_DIRECTION  Direction,
  IN OUT UINTN                     *BufferSize,
  IN OUT VOID                      *Buffer
  )
{
  USB_XDCI_DEV_CONTEXT              *UsbFuncIoDevPtr;
  USB_DEV_CORE                      *UsbDeviceCorePtr;
  XDCI_CORE_HANDLE                  *XdciCorePtr;
  EFI_STATUS                        Status;
  USB_XFER_REQUEST                  Xfer_req;
  UINT32                            EndPoint;

  DEBUG ((USB_FUIO_DEBUG_LOAD, "\n FU:Transfer - Entry\n"));
  DEBUG ((USB_FUIO_DEBUG_LOAD, "\n FU:EndpointIndex 0x%02x\n", EndpointIndex));
  DEBUG ((USB_FUIO_DEBUG_LOAD, "\n FU:Direction 0x%02x\n", Direction));

  UsbFuncIoDevPtr = USBFUIO_CONTEXT_FROM_PROTOCOL (This);

  UsbDeviceCorePtr = UsbFuncIoDevPtr->DrvCore;
  XdciCorePtr = UsbDeviceCorePtr->controller_handle;
  EndPoint = usb_get_physical_ep_num (EndpointIndex, Direction ? UsbEpDirIn : UsbEpDirOut);

  Status = SetFnIoReqInfo (
             This,
             EndpointIndex,
             Direction,
             BufferSize,
             Buffer,
             &Xfer_req
             );

  if (EFI_ERROR(Status)) {
    DEBUG ((USB_FUIO_DEBUG_LOAD, "Set SetFnIoReqInfo - Error Stop!!!\n"));
    while(1);
    Status = EFI_DEVICE_ERROR;
    goto FUN_EXIT;
  }

  UsbFuncIoDevPtr->EndPointXferRec[EndPoint].EpNum = EndPoint;
  UsbFuncIoDevPtr->EndPointXferRec[EndPoint].Direction = Direction;
  UsbFuncIoDevPtr->EndPointXferRec[EndPoint].XferAddress = (UINTN)Buffer;
  UsbFuncIoDevPtr->EndPointXferRec[EndPoint].XferLength = (UINT32)(*BufferSize);
  UsbFuncIoDevPtr->EndPointXferRec[EndPoint].ActualXferLength = Xfer_req.xfer_len;
  UsbFuncIoDevPtr->EndPointXferRec[EndPoint].LogEpNum = EndpointIndex;
  UsbFuncIoDevPtr->EndPointXferRec[EndPoint].Complete = FALSE;
  UsbFuncIoDevPtr->EndPointXferRec[EndPoint].ZlpFlag = FALSE;
  UsbFuncIoDevPtr->EndPointXferRec[EndPoint].Ep0RxData = FALSE;


  Status = EFI_DEVICE_ERROR;
  switch (EndpointIndex) {
    case 0: // Control endpoint
      if (*BufferSize == 0) {
        if (Direction == EfiUsbEndpointDirectionDeviceTx) {
          Status = usb_device_ep0_tx_status(UsbDeviceCorePtr);
        } else {
          Status = usb_device_ep0_rx_status(UsbDeviceCorePtr);
        }
      } else if (Direction == EfiUsbEndpointDirectionDeviceTx) {
        Status = usb_device_ep_tx_data(UsbDeviceCorePtr, &Xfer_req);
      } else if (Direction == EfiUsbEndpointDirectionDeviceRx) {
        DEBUG ((USB_FUIO_DEBUG_LOAD, "\n Set Setup Package - ??? Stop!!!\n"));

        Status = usb_device_ep0_rx_setup (UsbDeviceCorePtr, XdciCorePtr->aligned_setup_buffer);
        if (!EFI_ERROR(Status)) {
          UsbFuncIoDevPtr->EndPointXferRec[EndPoint].Ep0RxData = TRUE;
        }

      }
      break;

    default:
      Status = EFI_SUCCESS;
      if (Direction == EfiUsbEndpointDirectionDeviceTx) {
        DEBUG ((USB_FUIO_DEBUG_LOAD, "\n EfiUsbEndpointDirectionDeviceTx Size = %d\n",(*BufferSize) ));
        Xfer_req.zlp = TRUE;
        if ((((*BufferSize) % 512) == 0) && ((*BufferSize) != 0) && (UsbFuncIoDevPtr->EndPointXferRec[EndPoint].ZlpSupport)) {
          UsbFuncIoDevPtr->EndPointXferRec[EndPoint].ZlpFlag = TRUE;
          DEBUG ((USB_FUIO_DEBUG_LOAD, "\n Set Zlp flag\n"));
        }
        Status = usb_device_ep_tx_data (UsbDeviceCorePtr, &Xfer_req);
      } else {
        DEBUG ((USB_FUIO_DEBUG_LOAD, "\n EfiUsbEndpointDirectionDeviceRx Size = %d\n",(*BufferSize) ));
        Status = usb_device_ep_rx_data (UsbDeviceCorePtr, &Xfer_req);
      }
      break;
  }

  if (EFI_ERROR(Status)) {
    goto FUN_EXIT;
  }

  if (Status != EFI_SUCCESS) {
    Status = EFI_DEVICE_ERROR;
  }

FUN_EXIT:

  DEBUG ((USB_FUIO_DEBUG_LOAD, "FU:Transfer - Exit %r\n", Status));
  return Status;
}


/**
  This function supplies power to the USB controller if needed, initialize
  hardware and internal data structures, and then return.
  The port must not be activated by this function.

  @param[in]  This              A pointer to the EFI_USBFN_IO_PROTOCOL instance.

  @retval EFI_SUCCESS           The function returned successfully.
  @retval EFI_INVALID_PARAMETER A parameter is invalid.
  @retval EFI_DEVICE_ERROR      The physical device reported an error.
**/
EFI_STATUS
EFIAPI
StartXdciController (
  IN EFI_USBFN_IO_PROTOCOL    *This
  )
{
  USB_XDCI_DEV_CONTEXT         *UsbFuncIoDevPtr;
  USB_DEV_CONFIG_PARAMS        ConfigParams;
  EFI_STATUS                   Status;

  Status = EFI_SUCCESS;
  UsbFuncIoDevPtr = USBFUIO_CONTEXT_FROM_PROTOCOL (This);

  if (UsbFuncIoDevPtr->StartUpController == TRUE) {
    goto EXIT_START_CONTROLLER;
  }

  ConfigParams.ControllerId = USB_ID_DWC_XDCI;
  ConfigParams.BaseAddress = (UINT32)UsbFuncIoDevPtr->XdciMmioBarAddr;
  ConfigParams.Role = USB_ROLE_DEVICE;
#ifdef SUPPORT_SUPER_SPEED
  ConfigParams.Speed = USB_SPEED_SUPER;
#else
  ConfigParams.Speed = USB_SPEED_HIGH;
#endif

  //*Vid = 0x8086;
  //*Pid = 0x0A65
  UsbFuncIoDevPtr->VendorId = USBFU_VID;
  UsbFuncIoDevPtr->DeviceId = USBFU_PID;
  UsbFuncIoDevPtr->StartUpController = TRUE;

  Status = usb_device_init (&ConfigParams, &UsbFuncIoDevPtr->DrvCore);
  if (Status != EFI_SUCCESS) {
    Status = EFI_DEVICE_ERROR;
    goto EXIT_START_CONTROLLER;
  }

  UsbFuncIoDevPtr->XdciDrvIfHandle = UsbFuncIoDevPtr->DrvCore->controller_handle;

EXIT_START_CONTROLLER:

  DEBUG ((USB_FUIO_DEBUG_LOAD, "StartXdciController - Exit :: %r\n", Status));
  return Status;
}


/**
  This function disables the hardware device by resetting the run/stop bit
  and power off the USB controller if needed.

  @param[in]  This              A pointer to the EFI_USBFN_IO_PROTOCOL instance.

  @retval EFI_SUCCESS           The function returned successfully.
  @retval EFI_INVALID_PARAMETER A parameter is invalid.
  @retval EFI_DEVICE_ERROR      The physical device reported an error.
**/
EFI_STATUS
EFIAPI
StopXdciController (
  IN EFI_USBFN_IO_PROTOCOL    *This
  )
{
  USB_XDCI_DEV_CONTEXT  *UsbFuncIoDevPtr;
  EFI_STATUS            DevStatus;

  UsbFuncIoDevPtr = USBFUIO_CONTEXT_FROM_PROTOCOL (This);
  DEBUG ((USB_FUIO_DEBUG_LOAD, "StopController - Entry\n"));

  if (UsbFuncIoDevPtr->StartUpController == FALSE) {
    DEBUG ((USB_FUIO_DEBUG_LOAD, "The Controller not yet start up skip deinit\n"));
    return EFI_SUCCESS;
  }

  if (This == NULL) {
    return EFI_INVALID_PARAMETER;
  }

  DevStatus = usb_device_deinit (UsbFuncIoDevPtr->DrvCore, TRUE);

  UsbFuncIoDevPtr->DrvCore = NULL;
  UsbFuncIoDevPtr->XdciDrvIfHandle = NULL;
  UsbFuncIoDevPtr->StartUpController = FALSE;

  if (DevStatus != EFI_SUCCESS) {
    return EFI_DEVICE_ERROR;
  }

  DEBUG ((USB_FUIO_DEBUG_LOAD, "StopController - Exit\n"));
  return EFI_SUCCESS;
}


/**
  This function sets the configuration policy for the specified non-control endpoint.
  Refer to the description for calling restrictions

  @param[in]  This              A pointer to the EFI_USBFN_IO_PROTOCOL instance.
  @param[in]  EndpointIndex     Indicates the non-control endpoint for
                                which the policy needs to be set.
  @param[in]  Direction         Direction of the endpoint.
  @param[in]  PolicyType        Policy type the user is trying to set for
                                the specified non-control endpoint.
  @param[in]  BufferSize        The size of the Buffer in bytes.
  @param[in]  Buffer            The new value for the policy parameter that
                                PolicyType specifies.


  @retval EFI_SUCCESS           The function returned successfully.
  @retval EFI_INVALID_PARAMETER A parameter is invalid.
  @retval EFI_DEVICE_ERROR      The physical device reported an error.
  @retval EFI_UNSUPPORTED       Changing this policy value is not supported.

**/
EFI_STATUS
EFIAPI
SetEndpointPolicy (
  IN EFI_USBFN_IO_PROTOCOL        *This,
  IN UINT8                        EndpointIndex,
  IN EFI_USBFN_ENDPOINT_DIRECTION Direction,
  IN EFI_USBFN_POLICY_TYPE        PolicyType,
  IN UINTN                        BufferSize,
  IN VOID                         *Buffer
  )
{
  USB_XDCI_DEV_CONTEXT  *UsbFuncIoDevPtr;
  EFI_STATUS            Status;
  UINT32                EndPoint;
  UINT8                 *FlagPtr;

  UsbFuncIoDevPtr = USBFUIO_CONTEXT_FROM_PROTOCOL (This);
  FlagPtr = NULL;

  switch (PolicyType) {
    case EfiUsbPolicyUndefined:
    case EfiUsbPolicyMaxTransactionSize:
    case EfiUsbPolicyZeroLengthTerminationSupport:

     Status = EFI_UNSUPPORTED;
     break;

    default:
     FlagPtr = Buffer;
     Status = EFI_SUCCESS;
     break;
  }

  if (BufferSize < 1) {
    Status = EFI_INVALID_PARAMETER;
  }

  if (EFI_ERROR(Status)) {
    DEBUG ((USB_FUIO_DEBUG_LOAD, "SetEndpointPolicy - ERROR %r\n", Status));
    return Status;
  }

  EndPoint = usb_get_physical_ep_num (EndpointIndex, Direction ? UsbEpDirIn : UsbEpDirOut);

  UsbFuncIoDevPtr->EndPointXferRec[EndPoint].ZlpSupport = *FlagPtr;

  return Status;
}


/**
  This function retrieves the configuration policy for the specified non-control
  endpoint. There are no associated calling restrictions for this function.

  @param[in]  This              A pointer to the EFI_USBFN_IO_PROTOCOL instance.
  @param[in]  EndpointIndex     Indicates the non-control endpoint for
                                which the policy needs to be set.
  @param[in]  Direction         Direction of the endpoint.
  @param[in]  PolicyType        Policy type the user is trying to set for
                                the specified non-control endpoint.
  @param[in]  BufferSize        The size of the Buffer in bytes.
  @param[in]  Buffer            The new value for the policy parameter that
                                PolicyType specifies.


  @retval EFI_SUCCESS           The function returned successfully.
  @retval EFI_INVALID_PARAMETER A parameter is invalid.
  @retval EFI_DEVICE_ERROR      The physical device reported an error.
  @retval EFI_UNSUPPORTED       Changing this policy value is not supported.
  @retval EFI_BUFFER_TOO_SMALL  Supplied buffer is not large enough to
                                hold requested policy value.

**/
EFI_STATUS
EFIAPI
GetEndpointPolicy (
  IN EFI_USBFN_IO_PROTOCOL        *This,
  IN UINT8                        EndpointIndex,
  //IN EFI_USB_ENDPOINT_DIRECTION   Direction,
  IN EFI_USBFN_ENDPOINT_DIRECTION Direction,
  IN EFI_USBFN_POLICY_TYPE        PolicyType,
  IN OUT UINTN                    *BufferSize,
  IN OUT VOID                     *Buffer
  )
{
  USB_XDCI_DEV_CONTEXT  *UsbFuncIoDevPtr;
  EFI_STATUS            Status;
  UINT32                EndPoint;
  UINT32                MaxPacketSize;
  BOOLEAN               SetFlag;

  UsbFuncIoDevPtr = USBFUIO_CONTEXT_FROM_PROTOCOL (This);
  MaxPacketSize = 0;
  SetFlag = FALSE;

  switch (PolicyType) {
    case EfiUsbPolicyUndefined:

     Status = EFI_UNSUPPORTED;
     break;

    case EfiUsbPolicyMaxTransactionSize:
    case EfiUsbPolicyZeroLengthTerminationSupport:
    default:
     if (Buffer == NULL) {
       Status = EFI_INVALID_PARAMETER;
     } else {
       Status = EFI_SUCCESS;
     }
     break;
  }

  EndPoint = usb_get_physical_ep_num (EndpointIndex, Direction ? UsbEpDirIn : UsbEpDirOut);

  if (EFI_ERROR(Status)) {
    DEBUG ((USB_FUIO_DEBUG_LOAD, "GetEndpointPolicy - ERROR %r\n", Status));
    return Status;
  }

  if (PolicyType == EfiUsbPolicyMaxTransactionSize) {

    if (*BufferSize < sizeof(UINT32)) {
       Status = EFI_INVALID_PARAMETER;
    } else {
      MaxPacketSize = MAX_TRANSFER_PACKET;
      CopyMem (Buffer, &MaxPacketSize, sizeof(UINT32));
    }

  } else if (PolicyType == EfiUsbPolicyZeroLengthTerminationSupport) {
    if (*BufferSize < sizeof(BOOLEAN)) {
       Status = EFI_INVALID_PARAMETER;
    } else {
      SetFlag = TRUE;
      CopyMem (Buffer, &SetFlag, sizeof(BOOLEAN));
    }

  } else if (PolicyType == EfiUsbPolicyZeroLengthTermination) {
    if (*BufferSize < sizeof(BOOLEAN)) {
       Status = EFI_INVALID_PARAMETER;
    } else {
      SetFlag =  UsbFuncIoDevPtr->EndPointXferRec[EndPoint].ZlpFlag;
      CopyMem (Buffer, &SetFlag, sizeof(BOOLEAN));
    }
  } else {
    Status = EFI_INVALID_PARAMETER;
  }

  return Status;
}

/**
  This function Configures endpoints based on supplied list of device and
  configuration descriptors

  @param[in]  This              A pointer to the EFI_USBFN_IO_PROTOCOL instance.
  @param[in]  DeviceInfo        A pointer to EFI_USBFN_DEVICE_INFO instance.
  @param[in]  SSDeviceInfo      A pointer to EFI_USBFN_SUPERSPEED_DEVICE_INFO instance

  @retval EFI_SUCCESS           The function returned successfully.
  @retval EFI_UNSUPPORTED	      This operation is not supported.

**/
EFI_STATUS
EFIAPI
ConfigureEnableEndpointsEx (
  IN EFI_USBFN_IO_PROTOCOL           *This,
  IN EFI_USB_DEVICE_INFO             *DeviceInfo,
  IN EFI_USB_SUPERSPEED_DEVICE_INFO  *SSDeviceInfo
  )
{
  //
  // Set Configure table
  //
  ConfigureEnableEndpoints(This,DeviceInfo);
  ConfigureEnableSSEndpoints(This,SSDeviceInfo);

  return EFI_SUCCESS;
}

EFI_STATUS
UsbFnInitDevice (
  IN EFI_USBFN_IO_PROTOCOL        *This
  )
{
  EFI_STATUS                   Status;
  USB_XDCI_DEV_CONTEXT         *UsbFuncIoDevPtr;

  Status = EFI_SUCCESS;
  UsbFuncIoDevPtr = USBFUIO_CONTEXT_FROM_PROTOCOL (This);

  PlatformSpecificInit ();

  UsbFuncIoDevPtr->StartUpController = FALSE;
  Status = StartXdciController (&UsbFuncIoDevPtr->UsbFunIoProtocol);
  if (EFI_ERROR (Status)) {
    Status = EFI_DEVICE_ERROR;
    goto DEV_INIT_EXIT;
  }

  Status = usb_device_connect (UsbFuncIoDevPtr->DrvCore);
  DEBUG ((USB_FUIO_DEBUG_LOAD, "usb_device_connect Status %x\n", Status));
  if (Status != EFI_SUCCESS) {
    Status = EFI_DEVICE_ERROR;
    goto DEV_INIT_EXIT;
  }


DEV_INIT_EXIT:

  return Status;
}

EFI_STATUS
StartController (
  IN EFI_USBFN_IO_PROTOCOL        *This
  )
{
  return EFI_SUCCESS;
  // return UsbFnInitDevice(This);
}


EFI_STATUS
UsbFnDeInitDevice (
  IN EFI_USBFN_IO_PROTOCOL        *This
  )
{
  EFI_STATUS                   Status;
  USB_XDCI_DEV_CONTEXT         *UsbFuncIoDevPtr;

  UsbFuncIoDevPtr = USBFUIO_CONTEXT_FROM_PROTOCOL (This);

  if (UsbFuncIoDevPtr->StartUpController == FALSE) {
    DEBUG ((USB_FUIO_DEBUG_LOAD, "UsbFn:StopController:The Controller not yet start up force return EFI_SUCCESS\n"));
    return EFI_SUCCESS;
  }

  //
  // disconnect
  //
  Status = usb_device_disconnect (UsbFuncIoDevPtr->DrvCore);
  DEBUG ((USB_FUIO_DEBUG_LOAD, "usb_device_disconnect Status %x\n", Status));
  if (Status != EFI_SUCCESS) {
    Status = EFI_DEVICE_ERROR;
    goto DEV_DEINIT_EXIT;
  }

  //
  // StopController
  //
  Status = StopXdciController (&UsbFuncIoDevPtr->UsbFunIoProtocol);
  UsbFuncIoDevPtr->StartUpController = FALSE;

DEV_DEINIT_EXIT:
  return Status;
}

EFI_STATUS
StopController (
  IN EFI_USBFN_IO_PROTOCOL        *This
  )
{
  return UsbFnDeInitDevice(This);
}

